手写分布式存储系统v0.2版本

2024-02-03 21:04

本文主要是介绍手写分布式存储系统v0.2版本,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言

上回说到 手写分布式存储系统v0.1版本 ,已经实现了通过监听TCP端口并将数据写到本地磁盘的功能,今天咱们就继续往上面添砖加瓦

v0.2版本大致做以下功能

  • 实现滚动写文件

  • 代码优化

一、滚动写文件实现

由于咱们写文件是用的mmap进行文件写入,而mmap自身原因最多只能映射到不大于2G的文件。因此在一个磁盘文件写满后,咱们需要滚动写到一个新的文件中,基本上所有分布式存储系统都是这么实现的,如kakfa、pulsar、rocketmq等等。那咱们也自己尝试实现下,大致逻辑如下
在这里插入图片描述

这个过程中有几个点需要考虑

  • 如何判断文件写满了
  • 滚动前后文件名的变化规则

第一点可以考虑在内存中维护一个整型记录当前文件的大小,否则每次写数据时判断是否写满都要去查下linux会影响性能

第二点文件名变化规则的设计方式有较多中,例如每次写新的文件名都用最新的等。参考几个系统的实现后决定采用写指定名字的文件例如 “file”,当这个文件写满1个G时,将“file”改名为“file”加当前时间如“file-20240202”,然后再新建一个名为“file”的文件进行写入。这样就能保证“file”这个文件永远都是当前正在写入的文件,核心代码如下

    private boolean rollingFile() throws IOException {preFilepath =fileName+"-"+LocalDateTime.now().toString().replace(":","-").substring(0,19);File preFile = new File(preFilepath);boolean preFileExists = preFile.exists();if (!preFileExists) {this.fileChannel.force(false);boolean rename = file.renameTo(preFile);if (rename) {this.fileChannel = new RandomAccessFile(new File(fileName), "rw").getChannel();this.mappedByteBuffer = this.fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileSize);WROTE_POSITION_UPDATER.set(this, 0);return true;} else {LOG.error("TieredIndexFile#rollingFile: rename current file failed");return false;}}return false;}

二、代码优化

由于v0.1版本中实现的比较莽,因此现在需要进行一个简单的重构。重构后大致逻辑可以参考下面这张不规范的UML图,首先是抽象出一个LifecycleComponent接口,由于除了网络、持久化服务之外,未来咱们可能还会有其他的服务例如监控、插件服务等等,因此咱们需要对这些服务做一层统一的抽象,所有这些服务都要提供服务启动和服务停止的接口,这样设计之后再服务启动/停止时只需要对LifecycleComponent集合列表进行统一的启动/停止操作即可,代码维护起来也很舒服。

网络方面是通过NetServiceImpl方法初始化并启动Netty引导类ServerBootstrap,ServerBootstrap启动后会监听Linux机器的网络端口,在监听到有请求时会交给ServerHandler 进行处理,在ServerHandler这里可以调用LocalDataStorageImpl方法进行数据持久化,LocalDataStorageImpl是数据持久化的统一入口,咱们针对mmap写入方式抽象并实现了DefaultMappedFile,提供了真正的mmap写磁盘操作。基本大致逻辑就是如此,尽量不做过度的设计,好的系统是演变过来的,等未来发展到一定阶段后再根据情形进行分析优化
在这里插入图片描述

三、功能演示

  1. 开发完后,咱们就可以开始进行演示了,启动服务后当在控制台看到以下信息就知道服务已经正常启动,此时就可以发数据给服务端了
    在这里插入图片描述

  2. 通过指令能看到已经在目录下创建好对应的文件,由于是通过mmap方式写的数据,因此虽然咱们还没写数据到文件内,但是可以看到文件大小已经是100Byte了,这也是mmap的特点
    在这里插入图片描述

  3. 通过以下指令往8888端口发送数据
    (echo 'are you ok?'; sleep 2) | telnet 127.0.0.1 8888

  4. 通过控制台能够看到数据有写到磁盘,并且内存中维护的文件里存放数据的大小也在增加
    在这里插入图片描述

  5. 重复多次第4步,可以看到日志显示已到达文件大小触发文件滚动动作
    在这里插入图片描述

  6. 再看看linux文件系统可以看到,已经创建对应的文件testWrite-2024-02-02T19-35-20
    在这里插入图片描述

  7. 打印一下可以清晰的看到咱们刚刚请求的内容都被正确的持久化到磁盘中了
    在这里插入图片描述

四、总结

上面基本上就是 v0.2 版本的内容了,不难但是你会发现使用一个分布式存储系统、看它的源码的体验,跟你自己实现一遍是完全不同的,一个现成的组件就像是一架飞机,你看得到它的机翼、发动机等等,你知道它是这样设计的;但,它为什么是这样设计的呢?那样不可以吗,这类问题恐怕会想的比较少或者虽然想了一下但是转头就忘了。但是当你自己设计去实现的过程中,你会遇到种种问题需要你去反复思考以及做取舍等等,这些都是你真正意义上成长的过程,甚至有时还会顿悟为什么那个东西人家要这样设计,这些都是无比令人振奋的事情,这不就是生命的意义吗

这篇关于手写分布式存储系统v0.2版本的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/675402

相关文章

Android NDK版本迭代与FFmpeg交叉编译完全指南

《AndroidNDK版本迭代与FFmpeg交叉编译完全指南》在Android开发中,使用NDK进行原生代码开发是一项常见需求,特别是当我们需要集成FFmpeg这样的多媒体处理库时,本文将深入分析A... 目录一、android NDK版本迭代分界线二、FFmpeg交叉编译关键注意事项三、完整编译脚本示例四

查看MySQL数据库版本的四种方法

《查看MySQL数据库版本的四种方法》查看MySQL数据库的版本信息可以通过多种方法实现,包括使用命令行工具、SQL查询语句和图形化管理工具等,以下是详细的步骤和示例代码,需要的朋友可以参考下... 目录方法一:使用命令行工具1. 使用 mysql 命令示例:方法二:使用 mysqladmin 命令示例:方

Java版本不兼容问题详细解决方案步骤

《Java版本不兼容问题详细解决方案步骤》:本文主要介绍Java版本不兼容问题解决的相关资料,详细分析了问题原因,并提供了解决方案,包括统一JDK版本、修改项目配置和清理旧版本残留等步骤,需要的朋... 目录错误原因分析解决方案步骤第一步:统一 JDK 版本第二步:修改项目配置第三步:清理旧版本残留兼容性对

Redis实现分布式锁全解析之从原理到实践过程

《Redis实现分布式锁全解析之从原理到实践过程》:本文主要介绍Redis实现分布式锁全解析之从原理到实践过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、背景介绍二、解决方案(一)使用 SETNX 命令(二)设置锁的过期时间(三)解决锁的误删问题(四)Re

Gradle下如何搭建SpringCloud分布式环境

《Gradle下如何搭建SpringCloud分布式环境》:本文主要介绍Gradle下如何搭建SpringCloud分布式环境问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录Gradle下搭建SpringCloud分布式环境1.idea配置好gradle2.创建一个空的gr

Linux搭建单机MySQL8.0.26版本的操作方法

《Linux搭建单机MySQL8.0.26版本的操作方法》:本文主要介绍Linux搭建单机MySQL8.0.26版本的操作方法,本文通过图文并茂的形式给大家讲解的非常详细,感兴趣的朋友一起看看吧... 目录概述环境信息数据库服务安装步骤下载前置依赖服务下载方式一:进入官网下载,并上传到宿主机中,适合离线环境

C#使用StackExchange.Redis实现分布式锁的两种方式介绍

《C#使用StackExchange.Redis实现分布式锁的两种方式介绍》分布式锁在集群的架构中发挥着重要的作用,:本文主要介绍C#使用StackExchange.Redis实现分布式锁的... 目录自定义分布式锁获取锁释放锁自动续期StackExchange.Redis分布式锁获取锁释放锁自动续期分布式

深入理解Apache Kafka(分布式流处理平台)

《深入理解ApacheKafka(分布式流处理平台)》ApacheKafka作为现代分布式系统中的核心中间件,为构建高吞吐量、低延迟的数据管道提供了强大支持,本文将深入探讨Kafka的核心概念、架构... 目录引言一、Apache Kafka概述1.1 什么是Kafka?1.2 Kafka的核心概念二、Ka

浅谈配置MMCV环境,解决报错,版本不匹配问题

《浅谈配置MMCV环境,解决报错,版本不匹配问题》:本文主要介绍浅谈配置MMCV环境,解决报错,版本不匹配问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录配置MMCV环境,解决报错,版本不匹配错误示例正确示例总结配置MMCV环境,解决报错,版本不匹配在col

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整