对毫秒级中并发场景的思考

乐云一
  • 业务
  • 业务
About 1429 wordsAbout 5 min

对毫秒级中并发场景的思考

毫秒级业务在频繁进行消息交互的设计上一直都是马后炮式的困难点,何况是处于并发串联下的订单、执行、创建等等业务,遇到时头痛,解决时困惑,看穿时醒悟,有很多解决方案属实是相切恨晚。

因此在了解了各种毫秒级场景的类型后,记录下了本篇对此的思考。

首先基于我的理解定义,什么是毫秒级:从业务的入口到出口,以毫秒级速率推动业务流程

打个比方,应用A发起一条消息通过消息中间件被应用B接收,其中A->B 耗时1毫秒;B在消费消息后请求C, 其中B消费消息为5毫秒,B->C由于内接口调用无延时;C在完成逻辑后,将结果回执给A。

一个很简单的 A->B>C C->A,的链路。

在任何一个应用,上到微服务之间,单体架构接口之间,服务器之间,都会出现的一种任务流执行模式。

那么在这些服务于服务之间,随着代码优化、硬件能力...等的增强,速率也会越来越快,这也就很容易出现一种问题:

在以秒做规则的场景中出现实际偏差问题

比如我有一个执行动作的服务在C中,C规定有一秒只能执行一次,或者3秒执行2次;当触发动作发生时,C进行判断当前服务针对触发动作标识A的计数为几。

在目前如此的限流业务中,主流的设计一般分为这几种:

  • LUA脚本,缓存原子性控制
  • OAP计数器切面控制入口
  • 令牌桶限流
  • 漏桶算法
  • ....

在大多功能中,以上随便挑一种都可以实现以秒限流的设计,但是就引入了一个业务级别的问题。

在3秒执行2次的设计中,本该希望的是大体一秒一次的频率,由于毫秒级的触发,导致大多服务打在第一秒内,这就导致了两个问题:

  1. 业务功能上来看,3-1 = 2 秒时间这个功能是置灰的
  2. 设计上,不能以秒为单位判断,而是使用毫秒进行计数。

第一点属于我上述说的 在以秒做规则的场景中出现实际偏差问题 ,因此必须结合实际业务去考虑,这种设计一秒一次实际可能出现除了第一秒以外的时间置灰的场景允不允许出现;关于这点,设身处地的总结一下。

允许出现

正中靶心,这样恰好是限流设计存在的意义

不允许

如果功能设计,希望 3 - 1 = 1 ,那么就回归到了JAVA中老生常谈的一个问题:并发消费

如果需要以秒做计量单位去进行限流,那么当一批创建订单的服务并发的打在服务C上,一般来说有两个选择:

  1. 先到先得
  2. 最新者为优

分别对应 阻塞队列\并发锁 淘汰算法

第一种对于熟练开发的人来说,实现起来很容易,最简单的是直接使用一把偏向锁,将并发的秒级消费交给程序控制。

除此之外还可以使用但不限于:阻塞队列、CountDownLatch等JUC包类

不过我推荐使用Redis的Lua进行控制,原因无他:灵活 [可通过入参拼接] 、原子[Redis特性]、可视[缓存] 、高校

总而言之,除了上手难度,我暂时找不到不使用他的原因,除非项目未使用到Redis;

以下也是一种对于多少秒内,执行多少次,进行控制的Lua脚本:

local key = KEYS[1];
local value = ARGV[1];
local delValue = ARGV[2];
local limit = ARGV[3];
local seconds = ARGV[4];
redis.call('ZREMRANGEBYSCORE', key, '-inf', delValue)
local count = redis.call('ZCARD', key)
if tonumber(limit) and count >= tonumber(limit) then
    return 0
else
    redis.call('ZADD', key, value, value)
    redis.call('EXPIRE', key, seconds)
    return 1
end

特殊

在了解解决并发消费的方案中,一种很简单的设计也比较有意思:

既然在毫秒级的消费中出现并发于功能实现的冲突问题,那么我们是否可以在链路的某个节点上进行一个类似线程的睡眠动作?

比如A->B->C,当同一标识十条触发同时从A开始,我们在B上进行消费的随机睡眠,使之本来是同一秒的事件尽可能分散开来。

可以使用随机数\哈希\负载算法等办法,最终虽然执行速率上会慢上一秒点。

但是我们可以无视实际误差,去做到每一条并发消息都服务到位。

看视简单,但是却直击了并发的本质: 让并发不在并发

不过这种设计局限性很大,只适合于不在乎顺序的创建非关联关系的订单业务中。

总结

因为于设备的通讯设计中,出现了一个设备上报某个属性时,因为一些因素影响,导致在几毫秒内瞬间上报好几条属性。

这就导致了本来监听这个设备的其中一个属性变化值的功能混乱,在各方讨论中记录下这次经验的思考

Last update:
Contributors: LeYunone
Comments
  • Latest
  • Oldest
  • Hottest
Powered by Waline v2.14.7