支持 Kafka 和 RocketMQ 等消息引擎,滴滴开源分布式消息中间件 DDMQ

阅读数:5469 2019 年 1 月 30 日

滴滴出行消息队列团队近日开源了其内部广泛使用的分布式消息中间件产品 DDMQ,这是一款致力于提供低延迟、高并发、高可用、高可靠消息服务的企业级消息队列产品。 DDMQ 已经在滴滴内部稳定运行了两年多时间,支撑了网约车、小桔车服、地图、金融、智能驾驶、智慧交通、外卖等业务的稳定运行。日消息流水达到千亿级别,整体服务可用性超过 5 个 9。本文将从从产品特性、适用场景和架构设计等方面对 DDMQ 进行较为详细的介绍。

产品特性

DDMQ 具有如下的优秀特性:

  • 低延迟高吞吐:毫秒级延迟,单机百万条消息吞吐。

  • 丰富的消息类型:具备实时消息、延时消息和分布式事务消息。

  • 海量消息存储,支持消息回溯消费:支持 RocketMQ 和 Kafka 作为实时消息的存储引擎,使用 RocksDB 作为延时消息的存储引擎。

  • 秒级延时消息:支持单条消息设置精确到秒级的延迟时间,提供普通延时消息和循环延时消息。

  • 多语言客户端,提供了主流开发语言 SDK,包括 PHP, Java, Go, C/C++, Python,在 API 上保持着最易使用的 High Level 形式。

  • 多种消费方式:支持通过 Thrift RPC 拉取、HTTP 推送和第三方存储直写的方式消费消息。

  • 支持灵活的消息过滤和转换功能:通过使用 Groovy 脚本在服务端进行消息体的转换和过滤,能做有效减少客户端和服务器的数据传输量,减轻客户端处理消息的负载。

  • 统一的 Web 控制台:方便用户管理 Topic 等资源,通过控制台可以实现配置生产和消费的限流值、消费方式、Groovy 脚本、启停消费、重置消费进度等功能。

  • 完善的监控配套:提供模块的健康检查和消息堆积告警功能。

适用场景

消息队列作为构建现代分布式应用所必备的基础设施,有着广泛的应用场景。

  • 削峰填谷

在秒杀等场景下会导致短时间流量的暴涨,下游系统会因为缺少保护而过载甚至崩溃。DDMQ 提供的海量堆积能力和消费限流能够确保下游系统的平稳运行。

  • 异步解耦

    • 通过上下游系统的松耦合设计,可以保证上游系统不会因为下游系统的宕机而不可用。确保主流程的正常稳定运行。
  • 顺序消息

    • 现实中需要保证顺序的场景很多,比如订单系统中订单创建、支付、退款等流程,均需要保证顺序。 DDMQ 提供的顺序消费功能可以保证消息的先进先出。
  • 事务消息

    • 在微服务的场景下,通过 DDMQ 的事务消息能够达到分布式事务的最终一致性。

整体架构设计

下面这张图描述了 DDMQ 的总体架构。主要包括 Broker Cluster、Producer Proxy Cluster(以下简称 PProxy),Consumer Proxy Cluster(以下简称 CProxy),SDK,Console 等模块。

image

Broker Cluster 是 DDMQ 的消息存储层。使用 RocketMQ 作为实时消息的存储引擎(同时也支持使用 Kafka),Chronos 则是我们基于 RocksDB 自研的延时消息存储引擎。

PProxy 是 DDMQ 的生产代理服务, 内置 Thrift RPC Server,生产 SDK 通过 RPC 调用将消息发送给 PProxy,然后再由 PProxy 负责将消息生产到具体的 Broker 中去,在 PProxy 中我们实现了生产限流、重试和消息批量生产等功能。

CProxy 是 DDMQ 的消费代理服务,也内置了 Thrift RPC Server,当选择 SDK 消费时,消费方以 pull 的方式从 CProxy 中拉取消息,由于 CProxy 中的 PullBuffer 提前缓存了一定数量的待消费消息,因此消费的延迟很低。如果选择 HTTP 方式消费,则直接由 CProxy 将消息推送到业务指定的回调 URL 地址。在 CProxy 中,我们实现了消息过滤(通过编写 Groovy 脚本)、消息体转换(Transit)、重试、消费限流、顺序消费内部排序等功能。

Console 是 DDMQ 的控制台,用户通过控制台申请 Topic、Group 等资源。Topic 等数据会持久化到 MySQL 并推送到 Zookeeper;PProxy 和 CProxy 通过读取、监听 Zookeeper 上的 Topic 和 Group 数据来实时控制消息的生产和消费逻辑。

DDMQ 选择 Proxy+SDK 的架构,主要有这几个好处:

  • 方便多语言 SDK 的实现,由于滴滴内部使用的技术栈比较多,将主要逻辑放在 Proxy 上有利于降低 SDK 的复杂度,让 SDK 的开发速度大大加快。目前在滴滴内部支持 PHP, Go , C/C++, Java, Python, Node.js 等语言的 SDK 实现。

  • 存储层业务无感知,由于 Proxy 层屏蔽了后面的 RocketMQ 或 Kafka,使得存储层的切换可以做到业务无感知。

  • 加快新功能迭代速度,新功能的开发都在 Proxy 层实现,降低了 SDK 的升级频率。

延迟队列的设计

在开源版本的 RocketMQ 里提供了多种固定延迟 level 的延时消息支持,可以发送几个固定的延时时间的延时消息,比如延时 10s, 30s…,但是这种不同延时 level 的延时消息并不能满足滴滴内部众多业务方的需求,我们需要的是任意时间精度的延时。因次我们基于 RocksDB 自研了延时消息队列 Chronos,以 DDMQ 子模块的形式对外提供服务。

image

上面这张图描述了 Chronos 的总体结构;简单来说,生产 SDK 通过 PProxy 提供的 sendDelay RPC 将延时消息发送到 PProxy, 然后由 PProxy 将消息生产到 Chronos 固定的内部 topic 上(chronos_inner_xxx)。Chronos 模块再去消费 inner topic 的消息并将消息存储到本地的 RocksDB 里去。基于本地内置的 RocksDB 存储引擎构造一个时间轮服务,会将到期的消息再发送给 PProxy,以供业务方消费或 HTTP 推送给业务方。

对 RocketMQ 的扩展改造 --(broker 自动主从切换)

熟悉 RocketMQ 的同学应该知道,目前开源版本的 RocketMQ broker 是没有主从自动切换的。如果 Master 挂了,那就写不进去了。然后 Slave 只能提供只读的功能。当然如果你的 topic 在多个主节点上都创建了,虽然不会完全写不进去,但是对单分片顺序消费的场景,还是会产生影响。所以我们就自己加了一套主从自动切换的功能。

image

结合 RocketMQ 现有的结构,可以采用如上结构,探活采用多个节点同时向 master 发送探测消息的方式,相对心跳方式,提高了准确性。具体由 nameserver 完成,具体流程如下:

  1. 各 NameServer 通过抢占特定的临时节点,选出 Leader 节点;

  2. 各 NameServer 向 master 节点发送消息,根据发送发送探活消息失败率是否超过阈值判断是否健康,并将状态更新到此 brokername 下对应的 NameServer 节点中;

  3. NameServer 的 master 发现自己跟 Broker 的 master 链接异常,然后检查其他节点是否也发现 master 掉线,如果掉线数量超过阈值,启动切换流程;

  4. 将 broker master 切换为 slave;

  5. 从原有的 slave 中,选出 offset 最大的 broker,并将其切换为 master;

关于 DDMQ 部署安装,可参照 GitHub 的说明。

GitHub 仓库地址: https://github.com/didi/DDMQ

作者介绍

臧磊,毕业于北京大学软件工程研究所,滴滴出行自研消息中间件 DDMQ 开源负责人,曾就职于猿题库和今日头条,长期专注于消息队列等基础设施的研发工作。目前在滴滴出行负责 DDMQ 的产品云化和大数据生态建设等工作。

江海挺,毕业于北京大学软件工程研究所,滴滴出行自研消息中间件 DDMQ 的产品负责人,同时对于开源的 Kafka 和 RocketMQ 等消息系统的架构设计、运行维护有着深入的理解和丰富的经验。

收藏

评论

微博

发表评论

注册/登录 InfoQ 发表评论