pulsar原理浅析
[TOC]
前言
随着时代发展,技术更迭,不断有新的消息中间件出现并使用,本文就pulsar特性进行探讨和分析,阅读本文前,建议对业界通用消息队列有一定的学习和使用 (文中内容引用了部分互联网文档)
背景
- pulasr是什么:一个Pub/Sub模型的消息中间件
2021年pulsar在Yahoo内部开发
2016年开源并捐献给Apache
2018年成为Apache顶级项目
特点
- Pulsar的单个实例原生支持多个集群,可跨机房在集群间无缝的完成消息复制
- 极低的发布延迟和端到端延迟
- 可无缝扩展到超过一百万个Topic
- 简单的客户端API、支持Java、Go、Python和C++
- Topic支持多种订阅模式(独占订阅、共享订阅、故障转移订阅)
- 通过Apache BookKeeper 提供的持久化消息存储机制保证消息传递 ...
基础概念
pulsar的结构,由几个核心内容所组成
我们以上文结构进行分析
- Producer : 消息的生产者,负责发布消息到Topic
- Consumer : 消息的消费者,负责从Topic订阅消息
- Broker : 无状态服务层,负责接收和传递消息,集群负载均衡等工作,Broker 不会持久化保存元数据,因此可以快速的上、下线
- Apache BookKeeper : 有状态持久层,由一组 Bookie 存储节点组成,可以持久化地存储消息
Topic(主题)是某一种分类的名字,消息在 Topic 中可以被存储和发布。生产者往 Topic 中写消息,消费者从 Topic 中读消息
实现原理
- 通过上面的介绍,我们对pulasr有了一个整体的认识,但是消息是如何生产的?又是如何存储的?下游又是如何消费的呢?
broker和bookie
这里就不得聊一聊pulsar中比较有意思的broker和bookie了,我们在使用kafka
的时候,也经常会提到broker的概念,在kafka中broker扮演的角色作用主要是集群中的一个实例节点,但在pulsar中大不相同
broker是一个无状态组件,负责处理和负载均衡 producer 发出的消息,并将这些消息分派给 consumer
可以看到broker只是一个组件,并不负责存储消息,且是无状态的,便于快速上下线,更适合于云原生场景
bookie是BookKeeper集群中的存储节点,负责存储消息和游标
这里的设计,将 Broker 和 bookie 相互独立,方便实现独立的扩展以及独立的容错性 对于broker,在高负载场景下可以更方便的添加新节点 对于bookie,在存储不足时可以快速新增节点来平摊存储负载 在这种结构下消息存储分布均匀,单个分区数据量突出不会使整个集群出现木桶效应
生产到消费
有了以上的理解,消息的生产链路我们大概也能描绘出来
- Producer 生产消息
- 消息发送指定Topic
- 根据策略选择对应broker节点和Partition
- broker接收消息后,追加写入bookie分区下的segment分片
- 下游消费者拉取消息,按照指定模式消费
其中,生产模式分为 同步 和 异步
消费模式分为
- 独占(Exclusive) : 只能有一个消费者
- 灾备(Failover) : 支持多个消费者但同时只能一个消费,当上一消费者异常后按顺序依次执行消费
- 共享(Shared) : 多消费者共享消费,同一消息只会被一个消费者唯一消费
- KEY 共享模式(Key_Shared) : 消息根据key进行分发,同一key保证由同一消费者消费(
这样保证了同一KEY下的有序性
)
延时队列
pulsar的延时队列
,是另一个非常重要的特性
延时队列 : 生产消息时指定时间,消息在等待特定时间后再被消费,pulsar支持秒级延迟消息投递
这个特性比较有意思,利用这个功能我们可以做一些额外的事,或者取代原先的定时任务 比如错误重试,订单取消,相较于定时任务,使用延时队列
- 更快
- 更稳定
- 效率更高
实现
那,延时队列是如何实现的?
结合上图可以简单看一下,pulsar与内存
之中维护了一个delayed message tracker,它的作用即是存储所有的延时消息,底层存储结构为小顶堆
,当然,其中的index指向了具体的消息内容,包括Timestamp、LedgerID、EntryID等
每次消费者拉取数据时,都会优先检查延时队列
中的内容,如果发现堆顶的消息已经达到过期时间
,那么即可消费该消息
挑战
那么,通过对延时队列的了解,可能会遇到什么问题呢?
- delayed index 队列受内存限制 : 显然,你不能不限时间、不限数量的存储所有的延时消息
- delayed index 队列重建时间开销 : 假如pulsar服务发生了重启或其他异常情况,必然要面临延时队列重建的问题
还会不会有其他问题呢?问题又是否可以优化?等待思考
业界组件对比与应用前景
说了那么多,我到底要不要用pulsar?在什么情况下应该用它?
对比
我们先来看看业界通用组件的对比
分类 | 功能 | Kafka | Pulsar | RocketMQ | RabbitMQ |
---|---|---|---|---|---|
功能 | 消费推拉模式 | pull | pull+push | pull | push |
延迟队列 | 不支持 | 支持 | 支持 | 支持 | |
死信队列 | 不支持 | 支持 | 支持 | 支持 | |
消息回溯 | 支持 | 支持 | 支持 | 不支持 | |
消息持久化 | 支持 | 支持 | 支持 | 支持 | |
消息确认机制 | Offset | Offset+单条 | Offset | 单条 | |
消费模式 | 流模式 | 流模式+队列模式 | 广播模式+集群模式 | 队列模式 | |
性能 | 单机吞吐量 | 605MB/s | 605MB/s | 605MB/s | 38MB/s |
消息延迟 | 5ms | 5ms | ms级 | 微秒级 | |
运维 | 高可用 | 分布式架构 | 分布式架构 | 主从架构 | 主从架构 |
应用
- 常规消息中间件使用场景
- 服务请求异常,需要将异常请求放到单独的队列,隔 5 分钟后进行重试;
- 用户购买商品,但一直处于未支付状态,需要定期提醒用户支付,超时则关闭订单;
- 面试或者会议预约,在面试或者会议开始前半小时,发送通知再次提醒;
总结
pulsar作为新一代消息队列,有许多新生功能,可以用于解决特定场景下的业务痛点, 目前我们团队主要使用的消息中间件仍是kafka,但同时使用pulsar可以用于失败重试、定时取消等场景
相较于kafka,目前pulsar社区经验还没有那么丰富,虽然带来了新功能但同时也存在潜在的隐患和不稳定性,如果不需要使用到新特性
的话,选择kafka或许是个更好的选择
相关文档资料:
github地址 : github.com/apache/puls…
pulsar官网 : pulsar.apache.org/