计算与存储分离实践 swift 消息系统
消息系统
消息队列
hdfs
分布式文件系统
swift
存储
摘要: swift 是搜索事业部自主研发分布式消息系统, 它的主要存储基于分布式文件系统, 资源需求基于分布式调度系统 swift 能支持每秒数亿的消息传递, 支持 PB 级消息的存储
1. 相关背景
搜索事业部与计算平台事业部目前使用消息队列主要有以下三种场景:
1. 每天有上万张表需要通过 Build Service 来构建索引这些表主要来自主搜索, IGRAPH,Rank Service 等业务, 且每个表包含的文档数差别很大总数据量为 PB 级别, 总文档数达万亿级文档的大小不一, 小到几十 Byte 大到几百 KB 在 Build Service 内部, 文档处理与索引构建需要一个消息队列来传送消息因此在 build 时, 容易产生突发大流量 (几百 G / 秒, 几千万条 / 秒) 持续消息写入与读取
2. 搜索的在线服务如主搜索查询服务, RankService 打分服务或 IGRAPH 服务需要毫秒级的实时文档更新这些服务引擎基本上是多行多列结构, 即每一行是一个完整的服务单元, 由多台机器组成, 多行提升服务的总能力大的服务通常包含数百行, 所以一条实时消息通常会被消费数百次, 在线同时实时消费的机器规模也达上万台
3. 在线的实时消息主要来自离线实时模型训练, 用户的实时浏览点击加购行为或者商家的增删改宝贝等离线训练任务会同时启动几十万个 worker 对上千张表产生实时消息, 写请求每秒达千万次
对于这几种场景, 传统的消息队列 (如 Kafka 等) 要同时满足, 至少需要成百上千台物理机, 且系统还需要做改造来适用于每天上万个 topic 的增减和几十万的生产者与消费者同时读写消息另外这些机器的 failover 管理也是个大问题现实中, 搜索团队所有的机器都是由调度系统统一管理和复用, 没有专门的物理机可给消息系统独占使用
本文将介绍搜索事业部目前使用消息系统 swift 主要介绍系统结构和消息可靠传递机制这两方面最后介绍下 swift 系统在今年双十一期间的表现
2. Swift 介绍
传统的消息队列通常为消息的安全性, 一般先要求消息落盘到本机后才返回成功这限制的机器的迁移, 扩展和复用因为消息数据只存一两台机器, 机器迁移必然导致数据的迁移传统消息队列要有较高的性能, 通常先要解写磁盘的毛刺等 io 问题特别是机器与其它应用复用时 IO 问题并不好解决所以传统的消息队列一般要求机器独占使用
计算与存储分离一直是最近年来研究与应用的热点计算与存储分离带来最大的好处是机器的迁移与调度不再受到数据存储大小与位置的限制计算资源在调度系统的管理下可以近无限的扩展存储系统如 HDFS,PANGU 能提供的 PB 级的存储空间以及百万级的文件读写
计算与存储的分离在消息中间件系统中的应用还比较少, 主要的问题是传统的分布式文件系统的读写响应 latency 远大于本机的磁盘如果要保证消息先落盘, 导致整个请求的 latency 就会飙升, 影响整个消息系统的吞吐率但随着硬件水平的提升如 25G/100G 网络和 RDMA 等新技术的出现, 分布式文件系统也有了质的飞跃, 例如集团盘古 2.0 等系统为低延时高可靠的存储提供很好的存储平台
2.1 Swift 系统结构
Swift 消息系统是在计算与存储分离上的一次尝试它主要有以下特点:
首先, Swift 的每个计算结点都是无状态的, 即每个 worker 上除 log 记录, 不存储任何消息系统相关数据在 swift 消息系统中, 系统的状态数据存储在 zookeeper 上, 消息的内容则存储在分布式文件系统如 HDFS, PANGU 等上
其次, Swift 的每个计算结点都是等价的, 只要消息系统需要计算资源, 就可以通过调度系统不停的申请并提升整个消息系统的服务能力目前 Swift 可以跑在 Hippo 或者 Yarn 上面 Swift 消息系统每次申请的资源粒度也比较小, 可以充当调度系统的碎片利用者
最后, Swift 自身的 client 与 server 的消息读写协议, 能够保证消息高效可靠的传递
图 1 SWIFT 系统结构图
图 1 是 SWIFT 系统结构, 其主要分成 2 种 worker: Admin 和 BrokerAdmin 和 Broker 的资源分配与启动都是基于调度系统目前支持 Hippo 与 Yarn 这两种调度系统, 这 2 种 worker 都会有很多个实例, Broker worker 都是等价的, Admin worker 则有一个 leader, 其余的等价, 这些 worker 一般在 Docker 容器中工作
Admin 角色主要负责: 1. Topic 的增删改 2. Topic 对应物理 partition 与 broker 调度 3. Client 读写数据时物理 partition 的定位 4. 资源的调整, 如 broker 个数的增减等
Broker 角色主要负责: 1.partiton 相关的消息的读写 2. Partition 相关数据的管理如过期数据的清理等
2.2 Swift Topic 介绍
Swift 系统中的 topic 与其它消息系统的类似, 它是一堆相关消息的集合, 通常由业务自定义如图二所示, 在 swift 中 topic 是由 65536 个逻辑分区组成, 编号是 [0 - 65535] 在 Swift 消息系统内部, topic 是由 partition 组成的, 每个 partition 负责一个 range 的逻辑 partition 读写
在用户层面, 用户看不到 Swift 的物理 partition, 写消息时要么需要提供一个 hash 字段 (由 swift client 自动映射到相应的逻辑分区) 要么提供一个 0-65535 的逻辑编号 swift 根据 topic 下每个 partition 的服务 range, 把消息写入相应 partition 的 writer 中 Writer 可以通过同步与异步方式把消息 append 到对应的物理 partition 中
Topic 里物理 Partition 个数的多少影响整个 topic 的读写能力, 通过逻辑 partition 与物理 partition 映射, 当 topic 的服务能力不足时, 可以动态的扩展物理 partition 来提升读写能力另外, 物理 partition 是 Swift 的基本调度单元, admin 会根据每个 broker worker 负载, 尽可以平衡的调度 partition
图 2 swift topic 数据写入示意图
3. 可靠消息读写机制
先前提到传统的消息系统为了保证消息的可靠性, 在写消息时需要先落盘, 以防机器挂掉时, 消息不丢失 Swift 也提供类似的模式, 但落盘的对象是分布式文件系统如 HDFS 这种模式下正常写落盘消息延时的毫秒级, 当 HDFS 压力大时, 会变成秒级, 所以其性能不太稳定 Swift 设计了一种 client 与 broker 之间, broker 与 HDFS 之间的消息写入与确认协议来保证消息高效可靠的写入与持久化, 其机制类似 TCP 的滑动窗口协议
图 3 是消息异步安全发送的示意图 Broker 在分配到 partition 进行服务时, 会生成一个标记, 其由 partition 的版本号 (V),broker 加载 partition 时间戳 (S) 以及消息持久化的 checkpoint (C) 组成 Client 在向 admin 定位到 partition 所在 broker 的时也会获取 partition 的版本号 (V) 版本号 V 主要在 topic 属性发生变化时 (例如 partition 的个数等) 会更新时间戳每次 partition 发生重加载或调度都会发生变化
图 3 SWIFT 异步安全发送消息示意图
异步安全写消息工作流程如下:
1. 用户通过客户端写入一条消息, client 定位到写哪个物理 partition, 同时把消息写入到对应的 buffer 中用户写消息时, 还可以给每条消息设置一个递增编号, swift client 会自动映射写消息进度与编号的关系在异步模式的, client 会有专门的提交线程与 broker 进行通信
2. Client 第一次向 partition 发送消息时, broker 会验证 partition 的版本 V0, 匹配后才会接受消息, 同时会把三元组 (V,S, C) 返回 client 收到 accept 消息后, 会更新已接受消息的光标和协议的三元组信息
3. 客户端可以持续的写入消息, 同时 broker 那能 partition 中的消息做异步持久化, 当持久化成功时, 会更新持久化信息 (Ca) 持久化成功的消息在内存中不会马上删除, 只有内存不足时才会被回收
4. Client 的后台发送线程继续工作, 发送消息 b, 同时请求带上了 (V0,S0)
5. Broker 端验证 (V0,S0), 收受消息 b, 顺便把持久化信息也返回 (V0,S0,Ca), client 接收到 accept 信息后, 更新已发送的光标到 b, 同时更新已接受的光标到 a 消息 a 已经持久化成功, 在使用的内存将会被 writer 回收 Writer 更新 checkpoint (Ca) 给用户层, 表示消息 a 已经持久化
6. 同 3 一样, client 继续写消息 c,broker 继续持久化消息 b
7. 此时 partition 发生了调度 (例如被分配到了其它机器), 其 HDFS 上的文件消息马上可以读取到, 但内存中的消息会被清空此时 partition 加载时间戳变成了 S1Client 向 admin 重新定位到 partition 的服务 broker 写入的消息 c 和 (V0,S0)
8. Broker 检查 client 发送的 (V0,S0) 与自身的 (V0,S1) 不相等, 将拒绝此次消息的写入主要基于消息在 partition 内要求保序考虑此时 client 还不知道 b 是否被序列化成功, partition 重新被加载 b 是否被序列化成功的信息也会被丢弃 (无状态), 所以它也不知道因 Broker 返回 (V0,S1,C0), 要求 client 重新发送未持久化的所有消息
9. Client 重置已发送光标到 b 之前, 更新 S1 并重新发送消息 b 和 c
10. Broker 检验 client 的 (V0,S1) 并收受消息 b 和 c, 这时消息 b 会被再次持久化化到 HDFS 上 Client 重新更新已发送光标到 c 如果此后无新消息的写入, 且 buffer 中的消息还有未被持久化的, client 会发起一次空写操作获取最新的持久化信息
步骤 1-10 是异步消息写入的工作方式, 用户层可以获取到当前持久化消息的 checkpoint, 可以自己记录发送进度以便回滚如果不方便记录发送进度, 可以在写完一段数据后, 调用 flush 方法强制把数据从 client 的 buffer 放到 broker 的 buffer 中此时消息虽然没有被持久化, 但在 client 与 partition 各存一份所以只有在 broker 与 client 同时挂掉才出现消息丢失, 因此我们认为这种方法也是比较安全的
Swift partition 的写 buffer 缓存所有写入的消息, 只有当空间不足时, 消息内存空间才会被回收对文件上的消息读取, 也会以块 buffer 的方式做缓存 Partition 之间的 buffer 各文件 cache buffer 都是共享存储, 由统一的内存回收模块管理其保证冷门的 partition 基本不消耗资源, 热门的 partition 可以充分利用资源正常情况下, swift 的内存可以缓存数分钟的消息, 所以消费消息时基本上从内存读取, 读的性能也会很高效在这个协议下, 分布式文件系统偶尔抖动也不会影响消息的时效性, 实际上文件系统在数分钟内的挂机也不影响消息的实时传递
4. Swift IN 双十一
2017 年 swift 消息系统开始在搜索事业部与计算平台事业部大规模应用, 主要场景除主搜索外, 还包括 Porsche,K-monitor,IGraph, DII, OpenSearch,RankService 等业务另外, Swift 在蚂蚁金服, 阿里妈妈和神马事业部也有多套 swift 机群的部署
双十一当天, 同时服务的 topic 个数均值近万个, partition 个数达 10 万当天创建与删除的 topic 近 2 万个, 其主要来自 IGRAPH, RankService,DII 等业务索引的重建, 平时也差不多是这个数量级 当天 Swift 消息系统总共写入数万亿条消息, 读取数十万亿条消息, 读写比 3:1 总读写消息内容字节大小数 PB, 消息的内容是经过 Swift client 压缩, 一般消息压缩率是原始大小的 1/4 - 1/2 之间读写的最大 QPS 与均值都超亿条 / 秒, 读写请求的峰值与均值超千万次 / 秒在线与离线读写消息的 worker 超 20 万个 另外, swift 日常处理的数据与双十一的数值相差不大
5. 总结与展望
Swift 消息系统经过一年多的不断改进与优化, 目前每天能处理 PB 级与万亿级的消息, 但在不久的将来还需要解一些问题:
1. 超大量 client 如百万级的 client 写入, 涉及到的 partition 定位与 worker 的连接问题当 client 达百万时, 首先碰到的一个问题是连接数不够用, 目前离线的一个 client 写数据会对所有相关加载 partition 的 worker 产生连接, 如果 worker 有 N 个, partition 有 M 个, 其连接数达 N*M 个其次 partition 发生调度时, partition 的定位瞬间能打爆 Admin
2. 每秒百亿级别的消息读写时, 如何减少系统处理消息量 Swift 目前有 client 主动合并消息的优化, 但能合并的消息数量并不多, 能否在 broker 端进行消息合并与存储在大规模消息读写时如何降低对 HDFS 的压力 Swift 目前提供内存 topic 等来尽可能的减少消息落盘, 是否有更好的机制也需要探索
6. 相关职位招聘
发布时间: | 2017-11-17 | 工作地点: | 杭州市 | 工作年限: | 二年以上 |
所属部门: | 搜索事业部 | 学 历: | 本科 | 招聘人数: | 3 |
岗位描述:
参与阿里巴巴集团内部实时消息系统开发, 支持每秒万亿级别消息读写, 提供高可靠高性能高伸缩低延时的服务, 支撑电商金融物流文娱大数据人工智能搜索广告等各种业务场景
岗位要求:
1. 精通 C/C++ 语言和数据结构, 算法和数据结构基础扎实
2. 学习能力较强, 有很好的逻辑思维能力, 善于主动思考, 对技术有强烈激情
3. 具有优秀的分析和解决实际问题的能力和态度, 追求编写优雅的代码, 从技术趋势和思路上能影响技术团队;
4. 符合以下条件之一者优先
(1) 有互联网中间件 (数据消息服务等) 开发经验者优先
(2) 对 hbase/hadoop/cassandra/elasticsearch/rocksdb 等开源存储产品的一种或多种熟悉者优先
(3) 对 linux 内核原理或服务器硬件熟悉者优先
来源: https://yq.aliyun.com/articles/415657