300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > JuiceFS:写流程源码解析+刷盘+数据一致性分析

JuiceFS:写流程源码解析+刷盘+数据一致性分析

时间:2020-03-04 09:21:51

相关推荐

JuiceFS:写流程源码解析+刷盘+数据一致性分析

引言

juicefs是一款面向云原生设计的高性能分布式文件系统,其有如下特点:

数据存储和元数据存储分离,可以适配多种数据和元数据存储引擎。

后端存储可以直接对接各种对象存储,使用起来更方便,更加适配云服务趋势。

相关技术架构可直接参考:/docs/zh/community/architecture

写流程cache简要说明

cache分为两层,磁盘cache和内存cache

磁盘cache:数据刷盘时先写入磁盘cache,即本地文件系统,然后将文件上传到对象存储,然后再将本地文件系统文件删除掉

内存cache:内存cache只记录key和datasize

源码分析

写同步线程处理

func (fs *fileSystem) Write(cancel <-chan struct{}, in *fuse.WriteIn, data []byte) (written uint32, code fuse.Status)func (v *VFS) Write(ctx Context, ino Ino, buf []byte, off, fh uint64) (err syscall.Errno)// 获取filehandlefunc (v *VFS) findHandle(inode Ino, fh uint64) *handle// 加文件写锁,若有其他client进行并发写,等待func (h *handle) Wlock(ctx Context) bool// filewriter写数据func (f *fileWriter) Write(ctx meta.Context, off uint64, data []byte) syscall.Errno// 当前file使用超过1000个slice,或使用的buffersize大于预留,等待// 加filewriter mutex锁,使用cas操作f.Lock()// 等待正在进行的flush完成// 根据offset和length,拆分chunk,每个chunk单独写func (f *fileWriter) writeChunk(ctx meta.Context, indx uint32, off uint32, data []byte) syscall.Errno// 根据文件的chunk idx找到对应的chunkwriterfunc (f *fileWriter) findChunk(i uint32) *chunkWriter// 在chunkwriter中找到slicewriter,如果没有合适的slice,申请一个新的写func (c *chunkWriter) findWritableSlice(pos uint32, size uint32) *sliceWriter// 遍历每个slice,发现未覆盖的slice直接用,如果没有可用的slice,再外面申请一个// 对于每个chunk,第一个slice生成的时候启动一个异步线程,等待数据写盘后刷slice到对象存储的映射func (c *chunkWriter) commitThread() // slicewriter写数据func (s *sliceWriter) write(ctx meta.Context, off uint32, data []uint8) syscall.Errno// 将数据写入bufferfunc (s *wSlice) WriteAt(p []byte, off int64) (n int, err error)// 如果刚好写满一个chunk,异步刷盘(异步)func (s *sliceWriter) flushData()

slice刷盘

func (s *sliceWriter) flushData(// 生成sliceidfunc (s *sliceWriter) prepareID(// 刷盘func (s *wSlice) Finish(func (s *wSlice) FlushTo(// 遍历每一个block刷盘func (s *wSlice) upload(// 根据sliceid,chunkidx,blocksize生成key,用于对象存储文件名func (s *rSlice) key(// 进行slice数据写盘(异步)go func() {// 标记slice刷盘完成func (s *sliceWriter) markDone(

slice数据写盘

func (s *wSlice) upload(go func()// 写磁盘cache,用加速盘进行存储func (cache *cacheStore) stage// 生成路径,与对象存储相关路径一致,写数据到本地文件系统目录func (cache *cacheStore) flushPage(// 将数据写入磁盘cache,即使用os本地文件系统写文件func (f *File) Write(// 插入keymap,将key、datasize、atime,插入内存cachefunc (cache *cacheStore) add(// 若内存cache空间不足,触发淘汰// 数据上传到对象存储func (store *cachedStore) upload(// 上传对象存储func (store *cachedStore) put(// 更新内存cache中的key,和对应的datafunc (cache *cacheStore) uploaded(// 删除本地文件系统cache的文件os.Remove(stagingPath)

关键总结

多客户端如何保证数据一致性:不同客户端在读写时需要先调用SetLk、SetLkw、Flock接口,保证客户端之间的互斥。

并发读写如何保证数据一致性:使用filehandle上的读写锁保证数据一致性。

并发写如何保证内存原子性:使用filewriter上面的mutex锁保证原子性。

并发写如何保证元数据和数据的一致性:写数据到盘的过程中使用的是追加写,元数据没有修改时不会更新数据,保证原子性。写流程不会更新inode信息(如size等),只会更新block到存储对象的映射,因此不会出现更新inode信息并发的情况。

写文件如何保证inode数据和文件的一致性:不能保证,只有close文件后,才会更新inode信息,因此juicefs只能保证文件最终inode和文件信息的一致性。

slice中连续小io会在slice里面进行聚合,等待触发刷slice

参考文献

/docs/zh/community/internals

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。