消息数据隔离
单topic多group
消息数据隔离:给每个渠道,每种消息类型初始化一个线程池
可以通过nacos配置:dynamic-tp-nacos-dtp.yml 动态修改线程池的信息
去重实现逻辑:唯一key+Redis存储
- 通过Key从Redis获取记录
- 判断该Key在Redis的记录是否符合条件
- 符合条件的则去重,不符合条件的则重新塞进Redis更新记录
具体实现是采用基于Redis中的zset的滑动窗口去重,可以做到严格控制单位时间内的频次,属于限流的一种
redis的key增加前缀做到数据隔离(后期可能有动态更换去重方法的需求)使用雪花算法生成zset的唯一value*,score使用的是当前的时间戳*
消息丢弃
我们会在dev/pre环境设置白名单,只有在白名单的内的用户才能收到消息。而白名单的列表我们又可以维护在分布式配置中心上
一般将需要丢弃的模板id写在分布式配置中心
// 配置示例: [“1”,“2”]
消息链路追踪
在处理关键链路上打上对应的点位
打印埋点信息的核心逻辑是:
- 在入口侧(这里包括接口的入口以及刚消费Kafka的入口)需要打印出原始的信息。原始信息有了,才好对问题进行定位和排查,至少帮助我们复现
- 在处理过程中使用某个标识来标明处理的过程(10代表成功消费Kafka,20代表该消息已经被丢弃…),并且日志的格式是统一的这样后续我们可以统一清洗该埋点信息
接入graylog日志组件去查看日志,能够清楚的看到每个消息的 链路状态
austin-cron和austin-api在很大概率上是分开部署的,所以每一次调用接口都是远程调用。austin-cron定时任务读取CSV文件时,一行一行地加载数据到Redis的延迟队列中,积压到一定的size或者timeout才给接口austin-api接入层去处理,这是为了批量发送,batch处理,缓解文件消息量级过大,发送失败的问题。
用到线程池的两个地方:
- 消费数据隔离,根据不同的groupid创建不同的线程池
- austin-api在具体执行消费austin-api传递过来的接口参数的时候,设计了「线程池」进行接口调用的,更能充分利用系统资源(毕竟这次接口调用更多的是损耗网络的开销)
夜间屏蔽
只要把晚上的接收到的消息扔进Redis list,然后启个定时任务(每天早上9点)轮询该list是否有数据,如果有再重新做处理就完事了。
优雅关闭线程池
ThreadPoolTaskExecutor
在Java线程池提供了shutdown和shutdownNow供我们关闭线程,显然shutdown是优雅关闭线程池的方法。
使用Spring封装过的线程池ThreadPoolTaskExecutor,默认就会优雅关闭,因为它是实现了DisposableBean接口的。