0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

SENSORO 支撑百万级传感器的延时队列

SENSORO升哲科技 2022-08-26 11:44 次阅读

文/升哲科技刘鹏

摘要:本文主要描述升哲科技在打造物联智慧城市平台过程中关于如何实现延时队列服务的技术选型经验、延时队列服务的架构设计以及延时队列的底层细节实现原理。

背景

升哲科技是一家物联网与人工智能领域的国家高新技术企业、独角兽企业。

要打造物联智慧城市平台,在业务中涉及到各种延时任务的需求,例如设备定时空气开关,定时更新设备状态,定时提醒等等,基于这些需求,需要一个可靠、实时、海量的延时队列服务作为基础设施。

那么延时队列是什么呢?延时队列不同于消息队列按照先入先出(FIFO)的顺序来消费,而是根据消息指定时间延时消费。延时队列的使用在我们日常应用也非常多,比如:

· 在电商平台购物,在30分钟内没有支付自动取消订单;

· 待处理的工单超过1天未处理,二次发送提醒。

以上场景往往都需要延时队列实现。

早期延时队列的实现采用了数据库扫表方式,服务定期查询到期的任务,再通过Kafka来中转消息。当任务量小,延时精度要求低时扫表方式还能应对,然而随着业务增长、任务数量不断增多,延时时间精度要求也变高,扫表的方式已经无法满足我们的业务,于是我们开始探索新的技术方案来支撑百万级任务的延时队列。

延时队列的设计目标

1.高可用:多副本部署,保证服务不出现单点故障;

2.可扩展:可随着业务量增长来扩容,同时生产消费的请求延时也要低;

3.兼容旧接口,保证旧的服务不需要做任何修改;

4.消息传递可靠,至少保证一次送达。

技术选型

在开源社区已经存在一些解决方案:

方案描述
BeanstalkdBeanstalkd C语言实现,我们团队主要采用Golang和Java,二次开发有难度,beanstalkd不支持集群部署,高可用无法保证。
RabbitMQ延时队列RabbitMQ提供了延时队列插件,需要单独开启插件使用,其原理是通过死信队列实现。

NSQ

NSQ开源延时队列,NSQ支持延时队列。

DelayQueue延时队列

JDK中提供了一组实现延时队列的API,位于Java.util.concurrent包下DelayQueue。

时间轮算法

时间轮是一个算法,在 Netty、Akka、Quartz、ZooKeeper、Kafka等组件中都有使用,适合做统一调度器。

Redis Sorted Set

Redis Sorted Set 利用它的score属性,启用一个线程轮询,根据score获取超时的数据,然后触发超时操作。

考虑到运维难度和可扩展性,最终我们选择了开源项目Lmstfy作为基础来进行二次开发,选择Lmstfy的原因如下:

● 无状态服务,使用Redis来持久化,Redis的高可用方案已经非常成熟,在公/私有云都有Paas服务可使用;

● 支持扩容,可以配置多个Redis集群;

● 提供Java/Go/Rust/PHP客户端,监控面板完善;

● 采用Golang开发,高并发性能优秀,也方便后续二次开发。

整体架构设计

1.Delayer:无状态服务,提供给业务服务调用,兼容旧接口,在Delayer这一层直接操作Redis实现了任务删除和更新任务等等功能;

2.Lmstfy:无状态服务,提供延时队列基础服务,底层实现采用;

3.Redis Sentinel集群:保证Redis发生故障时自动主备切换。

pYYBAGMIPSWAadr5AAFsTrVOjrQ938.png

基础概念

● namespace -用于隔离业务,也可以通过配置namespace绑定不同的Redis集群;

● queue -队列,用区分同一业务不同消息类型;

● job -业务定义的业务,主要包含以下几个属性:

○ id:任务 ID,全局唯一;

○ delay:任务延时下发时间,单位是秒;

○ tries:任务最大重试次数,tries = N表示任务会最多下发 N次;

○ ttr(time to run):任务预期执行时间,超过 ttr则认为任务消费失败,触发任务自动重试。

数据存储

Lmstfy的 Redis存储由四部分组成:

● Timer:使用ZSET结构来存储延时任务,Score即任务的到期时间来排序;

● Ready queue - 使用LIST结构,存储已经到期的延时任务,实现FIFO消费;

● Deadletter-使用LIST结构,消费失败(重试次数到达上限)的任务,可以手动重新放回到队列;

● Job pool– string类型,存储消息meta信息

● Job mapping - string -存储应用自定义id和job的关联关系。

创建任务

创建任务会生成一个Job ID, Job ID包括写入时间戳、随机数和延时时长,然后将任务的meta信息写入Redis,Key为 j/{namespace}/queue/{id},当任务延时时间(delay)= 0,(实时消息队列我们使用Kafka)表示不需要延时则直接写到 Ready Queue(List),当延时时间(delay) = n(n > 0),表示需要延时,将延时加上当前系统时间作为绝对时间戳写到 Timer(sorted set),Timer的实现是利用 ZSET根据绝对时间戳进行排序,再由一个goroutine定期轮询将到期的任务通过 redis lua script来将数据转移到 Ready Queue(List)中。

任务消费

支持延时的任务队列本质上是两个数据结构的结合: Ready Queue(LIST)和 Sorted Set。

Sorted Set用来实现延时的部分,将任务按照到期时间戳升序存储,随后定期将到期的任务迁移至 Ready Queue(LIST)。

任务的具体内容只会存储一份在 Job pool里面,其他的如 Ready Queue只是存储Job id,这样可以节省内存空间。

任务更新和删除

Lmstfy本身不支持删除和更新,我们在Delayer层中在创建任务同时在Redis中创建了一个Mapping Key,客户端可以自定一个ID关联到Job id,Delayer提供了删除和更新(先删除再创建)API,我们业务还需要支持多次执行的功能,在处理Job Ack时根据任务参数重新插入队列,结合我们二次开发整体结构如下:

pYYBAGMIPVCAa4BwAADfigE8rpw668.png

性能表现

通过本地限定1核CPU压测生产消息数据如下:

200万任务量占内存600MB+,其中包括mapping key导致key数量翻倍。

以下是单核CPU的环境下压测结果,任务创建可高达1500TPS:

pYYBAGMIPXqARGSKAABKeHHOOaY266.png

延时任务到期时间比较分散的情况下,消费表现如下接800TPS:

poYBAGMIPYuAbM6lAABarCzSqO4714.png

总结

封装lmstfy的方案已足够支撑当前的使用场景,但还是有一些不足之处,比如:

● 在Delayer中操作Redis中的任务,无法保证原子性;

● 任务创建和消费另外会多一次网络请求,产生不必要的开销;

● 无法支持循环任务;

● Lmstfy采用HTTP协议,无法发挥更好性能。

未来,我们计划融合两个服务,完善任务CRUD功能,减少网络开销,并采用GRPC来替换HTTP协议通讯。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 大数据
    +关注

    关注

    64

    文章

    8660

    浏览量

    136610
  • 智慧城市
    +关注

    关注

    21

    文章

    4105

    浏览量

    95832
收藏 人收藏

    评论

    相关推荐

    选择传感器和设计模拟前端的过程

    和设计目标。 2. 选择合适的传感器并描述其电气输出。 3. 确定可以获得的最大增益。 4. 确定前置放大器的最优放大器。 5. 设计完整的传感器和前置放大器增益模块 6. 运行仿真。 7. 在构建硬件和进行校验
    发表于 11-24 08:21

    无锁队列解决的问题

    为什么需要无锁队列 无锁队列解决了什么问题?无锁队列解决了锁引起的问题。 cache失效 当CPU要访问主存的时候,这些数据首先要被copy到cache中,因为这些数据在不久的将来可能又会被处理器
    的头像 发表于 11-10 15:33 270次阅读
    无锁<b class='flag-5'>队列</b>解决的问题

    详解!CCD图像传感器和CMOS图像传感器,区别在哪?

    图像传感器和CMOS图像传感器的区别。 什么是CCD传感器? CCD(ChargeCoupledDevice),即“电荷耦合器件”,它是数字和机器视觉相机中用于捕捉静止和移动物体的一种传感器
    的头像 发表于 10-12 11:01 1119次阅读

    CCD图像传感器和CMOS图像传感器的区别详解

    传感器?CCD(ChargeCoupledDevice),即“电荷耦合器件”,它是数字和机器视觉相机中用于捕捉静止和移动物体的一种传感器,以百万像素为单位。数码相机规
    的头像 发表于 10-11 08:08 953次阅读
    CCD图像<b class='flag-5'>传感器</b>和CMOS图像<b class='flag-5'>传感器</b>的区别详解

    美泰公司实现MEMS惯性传感器在国际上首次百万级装车

    领先的MEMS汽车传感器斩获中国传感器产业 “杰出贡献奖”。     美泰公司获此荣誉,彰显了业界对公司全面布局汽车电子产业的高度肯定和认可,实现了MEMS惯性传感器在国际上首次百万
    的头像 发表于 09-15 09:43 1215次阅读

    集成温度传感器(2)#传感器

    传感器温度传感器
    未来加油dz
    发布于 :2023年08月20日 15:05:50

    温度传感器概述(2)#传感器

    传感器温度传感器
    未来加油dz
    发布于 :2023年08月20日 14:55:47

    温度传感器概述(1)#传感器

    传感器温度传感器
    未来加油dz
    发布于 :2023年08月20日 14:55:24

    微波传感器(2)#传感器

    传感器微波传感器
    未来加油dz
    发布于 :2023年08月20日 14:53:15

    光纤传感器(1)#传感器

    传感器光纤传感器
    未来加油dz
    发布于 :2023年08月20日 14:42:39

    集成温度传感器概述(2)#传感器

    传感器温度传感器
    未来加油dz
    发布于 :2023年08月20日 10:25:40

    光纤传感器(1)#传感器

    传感器光纤传感器
    未来加油dz
    发布于 :2023年08月20日 09:45:19

    “三个百万”订单,中国电科产业基础研究院MEMS传感器加速应用“上车”

    近日,中国电科产业基础研究院美泰科技微机电系统(MEMS)传感器市场拓展再获突破,自主研发的MEMS惯性器件与系统累计实现百万级装车,并获得多家重点新能源车企50多款新能源车型定点,MEMS
    的头像 发表于 06-14 08:45 428次阅读

    RTOS消息队列的应用

    基于RTOS的应用中,通常使用队列机制实现任务间的数据交互,一个应用程序可以有任意数量的消息队列,每个消息队列都有自己的用途。
    发表于 05-29 10:49 427次阅读
    RTOS消息<b class='flag-5'>队列</b>的应用

    利用C++提供的队列封装一个消息队列

    最近的C++项目中,需要用到消息队列,但是C++中又没有原生的消息队列,就在网上找了一下相关资料,利用C++提供的队列,自己封装一个消息队列,以后的项目也可以复用。
    的头像 发表于 05-20 15:16 1108次阅读
    利用C++提供的<b class='flag-5'>队列</b>封装一个消息<b class='flag-5'>队列</b>