作者:刘若愚 腾讯WXG后台开发工程师
导语定时器(Timer)是一种在业务开发中常用的组件,主要用在执行延时通知任务上 。本文以笔者在工作中的实践作为基础,介绍如何使用平时部门最常用的组件快速实现一个业务常用的分布式定时器服务 。同时介绍了过程中遇到问题的一些解决方案,希望能够给类似场景提供一些解决思路 。
1.什么是定时器定时器(Timer)是一种在指定时间开始执行某一任务的工具(也有周期性反复执行某一任务的Timer,我们这里暂不讨论) 。它常常与延迟队列这一概念关联 。那么在什么场景下我才需要使用定时器呢?
我们先看看以下业务场景:
- 当订单一直处于未支付状态时,如何及时地关闭订单,并退还库存?
- 如何定期检查处于退款状态的订单是否已经退款成功?
- 新创建店铺,N天内没有上传商品,系统如何知道该信息,并发送激活短信?
2.定时器的本质一个定时器本质上是这样的一个数据结构:deadline越近的任务拥有越高优先级,提供以下几种基本操作:
- Add 新增任务;
- Delete 删除任务;
- Run 执行到期的任务/到期通知对应业务处理;
- Update 更新到期时间 (可选) 。
它的设计目标通常包含以下几点要求:
- 支持任务提交(消息发布)、任务删除、任务通知(消息订阅)等基本功能 。
- 消息传输可靠性:消息进入延迟队列以后,保证至少被消费一次(到期通知保证At-least-once,追求Exactly-once) 。
- 数据可靠性:数据需要持久化,防止丢失 。
- 高可用性:至少得支持多实例部署 。挂掉一个实例后,还有后备实例继续提供服务,可横向扩展 。
- 实时性:尽最大努力准时交付信息,允许存在一定的时间误差,误差范围可控 。
- 有序链表,这个最直观,最好理解 。
- 堆,应用实例如JAVA JDK中的DelayQueue、Go内置的定时器等 。
- 时间轮/多级时间轮,应用实例如linux内核定时器、Netty工具类HashedWheelTimer、Kafka内部定时器等 。
文章插图
时间轮
如果任务的时间跨度很大,数量也多,传统的单轮时间轮会造成任务的round很大,单个格子的任务List很长,并会维持很长一段时间 。这时可将Wheel按时间粒度分级(与水表的思想很像),示意图如下所示:
文章插图
多级时间轮
时间轮是一种比较优雅的实现方式,且如果采用多级时间轮时其效率也是比较高的 。
4.业界实现方案业界对于定时器/延时队列的工程实践,则通常基于以下几种方案来实现:
- 基于redis ZSet实现 。
- 采用某些自带延时选项的队列实现,如RabbitMQ、Beanstalkd、腾讯TDMQ等 。
- 基于Timing-Wheel时间轮算法实现 。
推荐阅读
- 数据频繁变化的情况下,如何高效检索?
- SQL小技巧解决大问题:如何统计字符出现次数?
- 深入了解VLAN工作原理,不能错过干货
- Spring Boot 中如何统一 API 接口响应格式?
- 物业消防安全管理制度如何实施
- 金桔如何做饮品,青金桔发酵茶如何做
- 美国红枫,美国红枫小苗如何购买
- 古代是如何选妃的 看古代皇帝是如何选妃的?感觉身体被掏空
- 如何在个月内瘦30斤,月瘦10斤是否靠谱
- 新鲜玫瑰花瓣如何利用,菊花茶如何挑选