作者回复: 1. 一组consumer可以组成一个消费者组,共同消费一个topic中的多个分区,具体每个消费者消费哪一个或者几个分区,这个由动态重平衡算法来决定,一般是尽可能平均分配。 2. 对于同一个消费者组和同一个主题,每一个消费者可能会消费0个、1个或者多个分区,但是一个分区最多只能被一个消费者消费,不能被两个以上的消费者同时消费,会乱。但是对于不同消费者组的情况,同一个分区,可能被不同消费者组中的多个消费者同时消费,这时消费指针不同,不会乱。 3. PMQ定期删除MySQL中老数据,采用的是物理删除。关于pg的问题,我没有直接碰到过,建议可以看这个stackexchange上的帖子: https://dba.stackexchange.com/questions/123627/postgresql-data-files-have-size-more-than-data-itself
作者回复: 1. 没有特别的事务控制,就是Auto Commit。 2. 因为只有自增id一个索引(mysql对自增id索引有优化),插入很快,即使到千万级,也未见明显性能下降。 3. 是的,后台定期任务删除超过7天的老消息,通过自增id去两分找时间点,再通过id范围删除也很快。 4. 是的,因为没有索引,通过biz_id的查询,仅限大致知道时间范围后,去做迭代遍历。实践中,可以考虑将消息写一份到ES建立索引,携程就是这么干的,效果还不错。因为是基于MySQL存储消息,可以考虑阿里Canal从MySQL的从节点去消费消息,再发送到ES建索引,这样对Master没有性能影响。 5. PPD的数据库是用SSD,消息的存储性能对业务太关键,这点钱是值得花的,不必因小失大。
作者回复: 在PMQ的设计中,一张表设计的容量是700~1000万,七天后删除老消息,实际使用中一般每日消息量都是<=100万的(每日消息过多,可以进一步分区)。 你可以算一下bigint,每天100万,要多少年才能用完,应该是几辈子也用不完的,到那个时候这个系统早已被新技术淘汰。
作者回复: lag过大,一般可以通过多增加分区来分摊负载,既然增加分区了,当然可以适当增加消费者组中的消费者。
作者回复: 对,采用轮训polling,和Kafka一样。 消息拉取采用一种简单退避策略,从50ms起步,然后以50ms为步长不断往上加,最大到5秒。步长和最大等待都是可以配置。
作者回复: 1. 在生产端,PMQ主要统计DB写入延迟,这个主要在Broker上埋点统计的。在消费端,PMQ主要统计DB读取延迟,这个主要在Consumer端埋点统计的。 你说的那个方法,可以用来统计消息从生产进入DB到被消费者消费的延迟。这个在实践中我们发现意义并不大,因为只要消息不堆积(生产和消费速度匹配,或者消费速度>生产速度),基本上都是最多几十个ms的延迟。真正有价值的是最好消息堆积监控,也就是消费速度<生产速度的情况,这个需要告警扩容。 2. 堆积监控一般是后台线程异步去扫描数据库做的,发现异常则发邮件告警。当然可以发数据到Prometheus等监控系统,通过AlertManager或者Grafana等告警。
作者回复: 严格来讲是这样的。 但是完全强一致的HA成本太高,对于PPD这个量级规模,MySQL主从HA/最终一致是可以接收的。大不了挂了人肉修复一下,毕竟MySQL主挂是小概率事件。总体评估,人肉成本比完全强一致方案要低。
作者回复: 关于重平衡这块,PMQ 2.0做得是比较简单的,竞争协调就是就是通过元数据库DB记录状态来实现的,Broker都是状态的。 后面有一节会讲PMQ 3.0的重平衡实现,有一个集中式协调器负责协调。
作者回复: 1. PMQ3.0是支持延迟消息的。基本思路就是添加到期时间字段,然后消费者拉的时候看时间有没有到。 2. 消息主要按顺序插入和拉取,自增id是唯一主键,如果再加biz key索引,插入就会变慢。这个问题Cassandra/HBase也是一样的,你用了id做主键,再弄其它主键就需要二级索引机制,会变慢。而且引入Cassandra/HBase整个系统又变重了。如果真的需要高级查询,可以利用MySQL主从/阿里Canal机制,按需把消息再发到ES建立索引就好了,携程就是这样玩的。 3. Broker和存储的分离,Broker无状态可以水平扩展,是最大好处。另外MySQL的HA机制已经有成熟方案。 4. 谢谢!
作者回复: 后台线程异步批量写入的。中间即使由于故障集群重启,消费者可能重复消费(因为之前的消费偏移可能没有及时保存),所以是at lease once语义