共计 2820 个字符,预计需要花费 8 分钟才能阅读完成。
我的公众号:MarkerHub,Java 网站:https://markerhub.com
更多精选文章请点击:Java 笔记大全.md
小 Hub 领读:
20w+ 的推送用户,如何做到秒级并发实现,文中别离介绍了 MQ、传统定时工作以及 Redis 的 SortSet 队列三种计划,一一剖析可行性,并且最初给出了 Redis 的逻辑与局部代码实现。你学会了吗?
- 作者:我是林林
- https://www.cnblogs.com/linli…
前阵子开发了公司领劵核心的我的项目,这个我的项目是以 redis 作为关键技术落地的。
先说一下领劵核心的我的项目吧,这个我的项目就相似京东 app 的领劵核心,当然图是截取京东的,公司的就不截了。。。
其中有一个性能叫做领劵的订阅推送。
什么是领劵的订阅推送?
就是用户订阅了该劵的推送,在可支付前的一分钟就要把揭示信息推送到用户的 app 中。
原本这个订阅性能应该是音讯核心那边做的,但他们说这个短时间内做不了。所以让我这个负责优惠劵的做了 -.-!。具体计划就是到具体的推送工夫点了,coupon 零碎调用音讯核心的推送接口,把信息推送进来。
下们咱们剖析一下这个性能的业务情景。公司目前注册用户 6000W+,是哪家就不要打听了。。。比方有一张无门槛的优惠劵下单立减 20 元,那么抢这张劵的人就会比拟多,咱们激进预计 10W+,百万级别不好说。咱们初定为 20W 万人,那么这 20W 条推送信息要在一分钟推送实现!并且一个用户是能够订阅多张劵的。所以咱们晓得了这个订阅性能的有两个突出的难点:
- 推送的实效性:推送慢了,用户会埋怨没有及时告诉他们错过了开抢机会。
- 推送的体量大:爆款的神劵,人人都想抢!
然而推送体量又会影响到推送的实效性。这真是一个让人头疼的问题!
那就让咱们把问题一个个解决掉吧!
推送的实效性的问题:当用户在领劵核心订阅了某个劵的支付揭示后,在后盾就会生成一条用户的订阅揭示记录,外面记录了在哪个工夫点给用户发送推送信息。所以问题就变成了零碎如何疾速实时选出哪些要推送的记录!
计划 1:
MQ 的提早投递。MQ 尽管反对音讯的提早投递但尺度太大 1s 5s 10s 30s 1m,用来做准确工夫点投递不行!并且用户执行订阅之后又勾销订阅的话,要把收回去的 MQ 音讯 delete 掉这个操作有拍板大,短时间内难以落地!并且用户能够勾销之后再订阅,这又波及到去重的问题。所以 MQ 的计划否掉。
计划 2:
传统定时工作。这个相对来说就简略一点,用定时工作是去 db 外面 load 用户的订阅揭示记录,从中选出以后能够推送的记录。但有句话说得好任何脱离实际业务的设计都是耍流氓~。上面咱们就剖析一下传统的定时工作到底适不适宜咱们的这个业务!
是否反对多机同时跑 | 个别不能,同一时刻只能单机跑。 |
存储数据源 | 个别是 mysql 或者其它传统数据库,并且是单表存储 |
频率 | 反对秒、分、时、天,个别不能太快 |
综上所述咱们就晓得了个别传统的定时工作存在以下毛病:
1. 性能瓶颈。只有一台机在解决,在大体量数据背后力不从心!
2. 实效性差。定时工作的频率不能太高,太高会业务数据库造成很大的压力!
3. 单点故障。万一跑的那台机挂了,那整个业务不可用了 -。- 这是一个很可怕的事件!
所以传统定时工作也不太适宜这个业务。。。
那咱们是不是就大刀阔斧了呢?其实不是的! 咱们只有对传统的定时工作做一个简略的革新!就能够把它变成能够同时多机跑, 并且实效性能够准确到秒级,并且回绝单点故障的定时工作集群!这其中就要借助咱们的弱小的 redis 了。
计划 3:定时工作集群
首先咱们要定义定时工作集群要解决的三个问题!
1、实效性要高
2、吞吐量要大
3、服务要稳固,不能有单点故障
上面是整个定时工作集群的架构图。
架构很简略:咱们把用户的订阅推送记录存储到 redis 集群的 sortedSet 队列外面, 并且以揭示用户揭示工夫戳作为 score 值,而后在咱们个每业务 server 外面起一个定时器频率是秒级,我的设定就是 1s,而后通过负载平衡之后从某个队列外面获取要推送的用户记录进行推送。上面咱们剖析以下这个架构。
1、性能:除去带宽等其它因素,根本与机器数成线性相关。机器数量越多吞吐量越大,机器数量少时绝对的吞吐量就缩小。
2、实效性:进步到了秒级,成果还能够承受。
3、单点故障?不存在的!除非 redis 集群或者所有 server 全挂了。。。。
这里解析一下为什么用 redis?
第一 redis 能够作为一个高性能的存储 db,性能要比 MySQL 好很多,并且反对长久化,稳定性好。
第二 redis SortedSet 队列人造反对以工夫作为条件排序,完满满足咱们选出要推送的记录。
ok~ 既然计划曾经有了那如何在一天工夫内把这个计划落地呢?是的我设计出这个计划到根本编码实现,工夫就是一天。。。因为工夫太赶鸟。
首先咱们以 user_id 作为 key,而后 mod 队列数 hash 到 redis SortedSet 队列外面。为什么要这样呢,因为如果用户同时订阅了两张劵并且推送工夫很近,这样的两条推送就能够合并成一条~,并且这样 hash 也绝对平均。上面是局部代码的截图:
而后要决定队列的数量,个别失常来说咱们有多少台解决的服务器就定义多少条队列。因为队列太少,会造成队列竞争,太多可能会导致记录得不到及时处理。
然而最佳实际是队列数量应该是可动静配置化的,因为线上的集群机器数是会常常变的。大促的时候咱们会加机器是不是,并且业务量增长了,机器数也是会减少是不是~。所以我是借用了淘宝的 diamond 进行队列数的动静配置。
咱们每次从队列外面取多少条记录也是能够动静配置的
这样就能够随时依据理论的生产状况调整整个集群的吞吐量~。所以咱们的定时工作集群还是具备一个个性就是反对动静调整~。
最初一个要害组件就是负载平衡了。这个是十分重要的!因为这个做得不好就会可能导致多台机竞争同时解决一个队列,影响整个集群的效率!在工夫很紧的状况下我就用了一个简略实用的利用 redis 一个自增 key 而后 mod 队列数量算法。这样就很大水平上就保障不会有两台机器同时去竞争一条队列~.
最初咱们算一下整个集群的吞吐量
10(机器数)* 2000(一次拉取数)= 20000。而后以 MQ 的模式把音讯推送到音讯核心,发 MQ 是异步的,算上其它解决 0.5s。
其实发送 20W 的推送也就是 10 几 s 的事件。
ok~ 到这里咱们整个定时工作集群就差不多根本落地好了。如果你问我前面还有什么能够欠缺的话那就是:
* 加监控,集群怎么能够木有监控呢,万一出问题有工作沉积怎么办~
* 加上可视化界面。
* 最好有智能调度,减少工作优先级。优先级高的工作先运行嘛。
* 资源调度,万一机器数量不够,力不从心,优先保障重要工作执行。
目前我的项目已上火线,运行安稳~。
### 举荐浏览
Java 笔记大全.md
太赞了,这个 Java 网站,什么我的项目都有!https://markerhub.com
这个 B 站的 UP 主,讲的 java 真不错!