cxljs https://cxljs.github.io/ Recent content on cxljs Hugo en-us Fri, 01 Aug 2025 19:06:59 +0800 JuiceFS 设计和实现 https://cxljs.github.io/posts/juicefs/ Fri, 01 Aug 2025 19:06:59 +0800 https://cxljs.github.io/posts/juicefs/ <ul> <li><a href="#%E5%88%86%E5%B8%83%E5%BC%8F%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%8F%91%E5%B1%95">分布式文件系统的发展</a></li> <li><a href="#%E5%88%86%E5%B8%83%E5%BC%8F%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%9A%84%E6%8C%91%E6%88%98">分布式文件系统的挑战</a></li> <li><a href="#juicefs">JuiceFS</a> <ul> <li><a href="#%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8%E6%A8%A1%E5%9E%8B">文件存储模型</a></li> <li><a href="#%E5%85%83%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8%E6%A8%A1%E5%9E%8B">元数据存储模型</a></li> <li><a href="#%E6%9E%B6%E6%9E%84">架构</a></li> </ul> </li> </ul> <h1 id="分布式文件系统的发展">分布式文件系统的发展</h1> <p>Google GFS 的发表是分布式文件系统发展的里程碑,Meta + Data 的架构影响了后来的分布式系统设计。随后的 HDFS 是大数据时代最重要的存储系统之一,现在分布式文件系统最流行的2种接口协议是 POSIX 和 HDFS。</p> <p>随着云原生和对象存储的发展,数据系统的设计趋势是把数据放到对象存储,比如 autoMQ 把 Kafka 的数据放到对象存储,AWS 刚发布的基于对象存储的向量数据库。</p> <p>现在 LLM 时代对分布式文件系统的需求也有变化,相比大数据时代,AI 训练存储的更多是小文件,所以文件系统的元数据更多。LLM 时代的分布式文件系统还有一个热点是 GPU Direct FS。</p> <h1 id="分布式文件系统的挑战">分布式文件系统的挑战</h1> <p>文件系统的元数据组成一个 DAG,分布式文件系统的挑战之一在于:</p> <ol> <li>怎么存储这个 DAG?</li> <li>怎么高并发读写这个 DAG?</li> </ol> <p>常见思路:</p> <ol> <li>整个 DAG 存储在单个节点(主备模式),缺点是单节点吞吐量和容量有限,可能会成为系统瓶颈</li> <li>设计一个可扩展的存储 DAG 的系统,把 DAG 划分存储到多个节点,目前有相关的论文,但是没有这样做的开源项目(CubeFS 好像是?)</li> <li>转化成 KV/Table 数据模型存储在 KV/RDB</li> <li>不采用 Meta + Data 架构,把 Meta 和 Data 混合存储(10年前有这样做的系统,现在应该没有)</li> </ol> <h1 id="juicefs">JuiceFS</h1> <p>JuiceFS 是经典的 client-meta-data 架构,采用第3种思路存储元数据,支持 TiKV/MySQL/Etcd/Redis 等多个系统作为 Meta Service,数据放在对象存储,JuiceFS 本身是一个 client 层。</p> LevelDB #1 WAL https://cxljs.github.io/posts/leveldb-1-wal/ Sun, 09 Mar 2025 17:36:52 +0800 https://cxljs.github.io/posts/leveldb-1-wal/ <ul> <li><a href="#leveldb-overview">LevelDB Overview</a></li> <li><a href="#wal">WAL</a> <ul> <li><a href="#log-file-format">Log File Format</a></li> <li><a href="#log-writer">Log Writer</a></li> <li><a href="#log-reader">Log Reader</a></li> </ul> </li> </ul> <h1 id="leveldb-overview">LevelDB Overview</h1> <p>lsm-tree 设计思路:</p> <ol> <li>写日志,从而把写操作变成磁盘顺序写</li> <li>写先存储在内存,再批量写入新文件,保证每个文件的数据有序,方便合并,删除失效数据</li> <li>分层合并策略</li> </ol> <p>LevelDB 是 BigTable 的存储引擎,是最早流行的使用 lsm-tree 的存储引擎。</p> <p>LevelDB 架构图(在网上广为流传,应该是出自 MS 的一篇文章): <img src="img/arch.png" alt=""></p> <p>LevelDB 系列文章的顺序:</p> <ol> <li>WAL</li> <li>MemTable</li> <li>SSTables 格式,压缩、合并</li> <li>其他工程优化:Bloom Filter, Block Cache, Lock, Env</li> <li>MVCC 并发控制</li> <li>完整读写流程</li> </ol> <h1 id="wal">WAL</h1> <p>为了保证 MemTable 的数据不丢失,在写 MemTable 前会先写 WAL,重启时,重放 WAL 恢复 MemTable。正常情况一个 MemTable 对应一个 WAL,WAL 在 MemTable 成功落盘后删除。</p> <p>所以 WAL 应该有2个接口:<code>AddRecord()</code> 和 <code>Replay()</code>。</p> <p>LevelDB&rsquo;s WAL 分成 <code>log::Writer</code> 和 <code>log::Reader</code> 2个数据结构。</p> Redis 主流程实现 https://cxljs.github.io/posts/redis/ Sat, 13 Jul 2024 15:28:13 +0800 https://cxljs.github.io/posts/redis/ <ul> <li><a href="#util">Util</a></li> <li><a href="#%E7%BD%91%E7%BB%9C%E6%A1%86%E6%9E%B6">网络框架</a></li> <li><a href="#%E5%A4%84%E7%90%86%E8%AF%B7%E6%B1%82">处理请求</a> <ul> <li><a href="#%E6%8E%A5%E5%8F%97%E6%96%B0%E8%BF%9E%E6%8E%A5">接受新连接</a></li> <li><a href="#%E8%A7%A3%E6%9E%90%E5%91%BD%E4%BB%A4">解析命令</a></li> <li><a href="#%E6%89%A7%E8%A1%8C%E5%91%BD%E4%BB%A4">执行命令</a></li> <li><a href="#%E5%8F%91%E9%80%81%E5%9B%9E%E5%A4%8D">发送回复</a></li> </ul> </li> <li><a href="#servers-db-%E8%AE%BE%E8%AE%A1">Server&rsquo;s DB 设计</a></li> <li><a href="#%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84">数据结构</a></li> </ul> <p>Redis 是一个 in-memory data structures server, 在互联网应用广泛,常见的使用场景:</p> <ul> <li>作为其他系统的缓存,减少其他系统的负载,相比于本地缓存,Redis 可以让多个实例共享缓存的数据</li> <li>对延时要求高的场景</li> </ul> <p>在高性能的前提下,我觉得 Redis 的接口设计是它能从 memcached 等系统中脱颖而出的关键原因,Redis 支持 hash table, set, sorted set, vector set 等数据结构,对用户更加友好,还支持 timeseries, pub/sub, stream 等,使它有更多的使用场景。</p> <p>类似 S3, Redis API 被称为 Redis 协议,很多 KV 系统都支持 Redis 协议,比如阿里的 Tair。</p> <p>Redis 单机的整体架构主要分4个部分:网络框架、线程模型、内存数据结构、持久化。</p> <p>这篇文章讲 Redis 主流程的实现。</p> <h2 id="util">Util</h2> <p><code>lzf[.h/_c.c]</code>实现 lzf 压缩算法,RDB 持久化时默认使用 lzf 压缩 key&amp;value.</p> <p><code>zmalloc.[h/c]</code>是 malloc wrapper, 记录使用的堆内存量。</p> <p><code>sds.[h/c]</code>实现变长字符串类型,是内部最常用的数据结构,很多 buffer 的类型是 <code>sds</code>,分配内存的策略:</p>