实现【并发-顺序-规模可控】的消息转发平台

· 约 3 分钟 · 旧博客导入

大伙家里有nas的都知道,一般nas都可以配置消息通知,出什么问题会根据用户的配置发送消息提醒

但是我用的nas不支持钉钉、企业微信等即时通讯推送,只支持邮件、gotify、bark、slack之类的国际流行消息平台

我之前用的是苹果手机,苹果手机邮件提醒比较强烈,所以我直接用邮件推送,但是我现在用的安卓机,自带的邮件app连个震动都没有,这就很容易让我的硬盘错过最佳治疗时机

现在我用过gotify,这个东西是自己部署服务端的,但是客户端会被安卓手机杀后台,无论怎么设置都会被杀,而且说实话我也不太相信这个app在国内手机上会有很好的续航优化

想到之前我用server酱,把服务器通知转发到企业微信、钉钉上,现在工作了,这两个app无论如何都要安装,那我干脆自己写代码做个消息转发平台吧

既然要做这个项目,那就要有所提升,简单的协议转发感觉没什么意思。我忍不住幻想,如果我这个项目像server酱一样部署,如何在低成本的情况下支持大量生产者、消费者的并发通信

这里的主要问题是,像钉钉群机器人这样的推送方式是有频率限制的,一旦触发限制,消息就推不过去,这时就需要等待几秒再重试,为了等待期间不堵塞,就必须多开几个线程把后面的消息先取出来发。线程数也不能无限扩展,而且同一个推送终点不能多条线程同时推送(否则无法保证消息的顺序)

那咋办

没办法,只能控制一下

现在我想到两个方案

方案1:用固定数量的发送线程,每个线程对应1个rabbitmq队列,消息进队列时根据推送终点id进行哈希分片,然后放入对应的队列。这样做的效果就是同一个推送终点的消息始终会进同一条队列,不会出现多个线程同时推送到一个终点的情况。但是这样做的缺点就是,如果有一个推送终点阻塞了,会立即影响这条队列其他终点的及时推送,因为多个推送终点的消息会混在同一条队列里

image
image

方案2:用固定数量的发送线程,每个线程对应1个rabbitmq队列,每个推送终点独占一条线程。如果所有线程都被独占了,那就看看哪个线程对应的队列已空,把空队列的独占终点切换成新的终点并插入消息;如果没有空队列,则等待到有1条线程发送完毕变成空队列,再切换该线程的独占终点。这样做的效果就是,如果某个推送终点阻塞了,一段时间内不影响其他终点的推送。当然如果线程池里所有线程都阻塞了,那就会影响整个平台所有消息的及时推送,而且在并发规模比较大的情况下,全局扫描队列长度的操作也会让CPU燥热起来

image
image

最终我使用了第二种方案,因为方案1是我写文章的时候想到的,写代码的时候只想到方案2。俺寻思方案2可能对大量不同终点的零碎消息性能更好,因为零碎消息很快就发完了,就算有几个消息堵了,分配器也可以一次性回收很多空队列,然后再发下一波;方案1在应对大量零碎消息的时候,几个消息堵塞会造成多个终点的推送堵塞,不是很健康

其实把两种方案结合一下可能最好,把方案2头顶上加个哈希分片,就能把方案2优化成集!群!

image
image

毕竟分布式map实现难度肯定比哈希分片难度高

当然用两级哈希分片应该也行

查找文章

↑↓ 选择 · Enter 打开 · Esc 关闭 查看全部结果