初冬一个晴朗的午后,从地坛出发,经交道口三条,过圆恩寺胡同,一路走到什刹海。当天天气出奇的好,在太阳的透照下,整个胡同片区懒洋洋的,心里也不由的很轻快。
真香——MacBook Pro 2016 Genius Bar 更换键盘小记
研究生毕业时,去网易游戏实习攒了点钱,便想入手垂涎了好久的程序员生产力工具—— MacBook Pro。适逢新版发售,等到 2016 年底,新版甫一上市,便从官网下单了一台 pro 入门版:13 寸两口不带 bar 。不过哪怕是入门版,也要一万多大洋,还两个口,还不带 bar。
不带 bar 尚可接受,毕竟 vim 党还是喜欢能按的下去的 Esc 。但两个口——于是默默了去京东下单了几个扩展口,彼时 tpye c 尚不流行,选择无几。
到货后满心欢喜打开,惊艳异常,是醉人的新配色——深空灰、是史无前例的轻薄、是类 Unix 系统加上舒服的 UI。于是将之前的小嘀咕抛诸脑后,嗯,真香。
MIT 6.824 2020 Raft 实现细节备忘
引子
18年的时候做过一些 6.824,旧文在此,无奈做到 Part 2C,无论如何也跑不过测试,便一直搁置起来。但在后来的日子,却时时念起此门神课,心下伤感。拖到今日,终于可以来还愿了。
这次能跑过所有测试,原因有三:一来,之前做过一次,很多原理还留有印象;二来,这一年多在工作上有了很多分布式系统的实践;三来,golang 的驾驭上也精进了一些。但是在做的过程中,仍然遇到了大量令人纠结的细节,为了方便日后回顾,将这些细节梳理一下,记在此处。若能好巧对其他做此门课的人有些微启发,则又是快事一件了。
6.824 与 Raft
6.824 是一门关于分布式系统的非常棒的公开课,做课程实验的过程中时时惊叹于其构思之精巧、材料准备之翔实。MIT 的大师们能将这样精华的课程开放出来,实乃名校和大师们的气度,更是我们计算机人的幸事。
Raft 是一个面向理解的分布式共识(consensus)协议。分布式共识算法是分布式领域非常非常经典的问题,同时也是分布式系统中非常难的一块,直观的说,就如同流沙上打下分布式系统大楼的地基。不可靠的网络、易故障的主机,造成的状态变化之复杂,实在不是一般人能在脑中模拟得了的。本人愚钝,只能是感性把握加细节堆叠,堪堪有些认识。说回 Raft,有同领域 Paxos 珠玉在前,何以 Raft 仍能脱颖而出?应该是抓住了以下两点:
- 易于理解。Paxos 是出了名的难以理解,因此也就难以飞入寻常百姓家。而 Raft 通过解耦出多个模块,将算法复杂度进行降维,大大降低了一般人的理解难度。此外,Raft 还有很多精巧的设计,以尽可能避免引入复杂度,从而进一步减轻大家的心智负担。
- 易于实现。易于理解客观上会导致利于实现,但不等同于就能据此产出优秀系统。如果理解流于感性,则实现成空中楼阁。Raft 论文的厉害之处就在于既有感性把握又有细节组织,几乎就是一个系统的设计文档,还是详细设计文档。
要想做好该实验,需要涉猎大量的材料,我把实验中提到的和我看到的汇总在文末。当然,还有英文劝退。虽然我最后测试用例都过了,但仍有很多没实现好的点以及不理解之处。
注:后续,2023 年又做了一次,终于理清楚了大部分点。
Golang 笔记(一):值方法和指针方法(Value Methods vs Pointer Methods)
Kafka —— 弥合日志系统和消息队列的鸿沟
概览
Kafka (该论文发表于2011年6月**[1]**)是日志处理和消息队列系统的集大成者。较低的延迟、极高的容量和吞吐,使其可以应用于在线服务和离线业务。为了兼顾性能和可扩展性,Kafka 做了一些看起来反直觉但是却很实用的设计。例行总结一下其设计特点:
面向存储的消息队列:意味在近实时的情况下能够将传统消息队列的存储增加几个数量级。实现原理是充分利用了磁盘的顺序写和操作系统自身的缓存;此外为了提高访盘、传输效率,使用了文件分段、段首索引、零拷贝和批量拉取等技术。
灵活的生产消费方式:总体而言是基于主题粒度的发布订阅式架构,并且既支持组内多消费者互斥消费,也支持不同消费者组间的重复消费。这里面涉及到消息队列的两个核心设计选择:pull 式消费以及客户端侧存储消费进度。拉式消费可能会导致空轮询以及稍微的延迟,好处在于灵活;客户端存储消费进度可以使的 broker 无状态,以进行灵活伸缩和容错。为了简化实现,消费时,每个分区最多为一个消费者所消费。
Zookeeper 存储元信息:利用分布式一致性组件 Zookeeper 以注册表的形式存储系统元信息,包括 broker 和消费者的存活信息、消费者和分区间的对应关系、每个分区的消费进度等等。Zookeeper 作为一个前缀树形式组织 KV、支持发布订阅的高可用组件,可以满足 Kafka 进行消费协调和进度保存的协作需求。
分区级别的多副本设计:这一点在论文中还没实现,应该是后来系统开源演进时加上的。利用该条可以实现对 broker 的容错。
简洁强大的消费接口:Kafka 的客户端一般提供两层接口抽象。包括无需关注分区和偏移量信息的高层(high-level)简单读写接口,以及可以灵活控制分区组织和消费进度的低层(low-level)接口。论文中只提到了前者,以表现其简洁。
Bazel 构建 Golang 项目
Spark 系统的理论基石 —— RDD
Python3 生成器(Generator)概念浅析
数据结构与算法(三):拆分二叉搜索树
煮红果记
季秋时节,各种果子纷至沓来。山楂,我们那叫山里红,北京好像称红果。老北京一道有名的菜便是“炒红果”。这天去菜市场,发现今年的个大成色好,便赶紧买了些来。
Hexo Next 主题进阶设置
在使用 github pages + hexo + next 搭建了 Hexo 博客 并用了一段时间后,想对博客进一步进行定制和美化,记录在这里。过程中发现英文文档要比中文文档详细很多,基本上 thems/next/_config.yaml 中所涉及到的所有设置都有讲解,所以如果英文不错,还是看英文文档吧:https://theme-next.org/docs/ 。
此外,每次修改后记得及时用 hexo s
在本地http://localhost:4000/
部署查看效果,看是否达到了自己的预期。
Ray 源码解析(二):资源抽象和调度策略
上一篇讲了待调度任务的组织形式,这一篇来继续挑软骨头啃:节点资源抽象和调度策略。
引子
由于 Ray 支持对任务进行显式的资源约束,因此需要对所有节点的资源进行硬件无关的抽象,将所有资源归一化管理,以在逻辑层面对资源进行增删。当有节点加入,需要感知其资源总量大小;当有任务调度,需要寻找满足约束节点;当任务调度成功,可以获取剩余可用资源等等。
Ray 除了对标准资源如 CPU,GPU 的支持,还支持对用户自定义 label 的资源的调度。用户在启动节点(ray start --resources <resources>
)指定该节点具有某种类别的资源(比如说 memory,bandwidth,某种型号的 GPU 等等)的总量,在定义 remote 函数时指定任务使用多少该类别的资源,Ray 的调度器在调度该任务时,就会按照用户自定义的资源需求将其调度到特定的机器上去。这是一种用户代码和调度器交互的一种有趣设计。
对于调度策略,由于 Ray 是去中心化的调度,很容易存在不一致状态。最简单的在实践中反而是统计最优的——对于每个任务找到符合资源约束的节点,随机选择一个,将任务调度过去。