private int status= Status.WaitPut.ordinal();
运行原理
-
用Map来存储元数据。id作为key,整个消息结构序列化(json/…)之后作为value,放入元消息池中。
-
将id放入其中(有N个)一个zset有序列表中,以createTime+delay+priority作为score。修改状态为正在延迟中
-
使用timer实时监控zset有序列表中top 10的数据 。 如果数据score<=当前时间毫秒就取出来,根据topic重新放入一个新的可消费列表(list)中,在zset中删除已经取出来的数据,并修改状态为待消费
-
客户端获取数据只需要从可消费队列中获取就可以了。并且状态必须为待消费 运行时间需要<=当前时间的 如果不满足 重新放入zset列表中,修改状态为正在延迟。如果满足修改状态为已消费。或者直接删除元数据。
客户端
因为涉及到不同程序语言的问题,所以当前默认支持http访问方式。
-
添加延时消息添加成功之后返回消费唯一ID POST /push {……消息体}
-
删除延时消息 需要传递消息ID GET /delete?id=
-
恢复延时消息 GET /reStore?expire=true|false expire是否恢复已过期未执行的消息。
-
恢复单个延时消息 需要传递消息ID GET /reStore/id
-
获取消息 需要长连接 GET /get/topic
用Nginx暴露服务,配置为轮询 在添加延迟消息的时候就可以流量平均分配。
目前系统中客户端并没有采用HTTP长连接的方式来消费消息,而是采用MQ的方式来消费数据这样客户端就可以不用关心延迟消息队列。只需要在发送MQ的时候拦截一下 如果是延迟消息就用延迟消息系统处理。
消息可恢复
实现恢复的原理 正常情况下一般都是记录日志,比如mysql的binlog等。
这里我们直接采用mysql数据库作为记录日志。
目前创建以下2张表:
-
消息表 字段包括整个消息体
-
消息流转表 字段包括消息ID、变更状态、变更时间、zset扫描线程Name、host/ip
定义zset扫描线程Name是为了更清楚的看到消息被分发到具体哪个zset中。前提是zset的key和监控zset的线程名称要有点关系 这里也可以是zset key。
支持消息恢复
假如redis服务器宕机了,重启之后发现数据也没有了。所以这个恢复是很有必要的,只需要从表1也就是消息表中把消息状态不等于已消费的数据全部重新分发到延迟队列中去,然后同步一下状态就可以了。
当然恢复单个任务也可以这么干。
数据表设计
这里,我就直接给出创建数据表的SQL语句。
DROP TABLE IF EXISTS mykit_delay_queue_job
;
CREATE TABLE mykit_delay_queue_job
(
id
varchar(128) NOT NULL,
bizkey
varchar(128) DEFAULT NULL,
topic
varchar(128) DEFAULT NULL,
subtopic
varchar(250) DEFAULT NULL,
delay
bigint(20) DEFAULT NULL,
create_time
bigint(20) DEFAULT NULL,
body
text,
status
int(11) DEFAULT NULL,
ttl
int(11) DEFAULT NULL,
update_time
datetime(3) DEFAULT NULL,
PRIMARY KEY (id
),
KEY mykit_delay_queue_job_ID_STATUS
(id
,status
),
KEY mykit_delay_queue_job_STATUS
(status
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
– Table structure for mykit_delay_queue_job_log
DROP TABLE IF EXISTS mykit_delay_queue_job_log
;
CREATE TABLE mykit_delay_queue_job_log
(
id
varchar(128) NOT NULL,
status
int(11) DEFAULT NULL,
thread
varchar(60) DEFAULT NULL,
update_time
datetime(3) DEFAULT NULL,
host
varchar(128) DEFAULT NULL,
KEY mykit_delay_queue_job_LOG_ID_STATUS
(id
,status
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
关于高可用
分布式协调还是选用zookeeper。
如果有多个实例最多同时只能有1个实例工作 这样就避免了分布式竞争锁带来的坏处,当然如果业务需要多个实例同时工作也是支持的,也就是一个消息最多只能有1个实例处理,可以选用zookeeper或者redis就能实现分布式锁了。
最终做了一下测试多实例同时运行,可能因为会涉及到锁的问题性能有所下降,反而单机效果很好。所以比较推荐基于docker的主备部署模式。
-
支持 master,slave (HA)需要配置
mykit.delay.registry.serverList
zk集群地址列表 -
支持 cluster 会涉及到分布式锁竞争 效果不是很明显 分布式锁采用
redis
的setNx
实现 -
StandAlone
目前,经过测试,推荐使用master slave的模式,并且,在升级版本中,进一步增强了Master Slave模式。后期会优化Cluster模式。
为了提供一个统一的精准定时任务和延时队列框架,mykit-delay提供了HTTP Rest接口和RPC方式供其他业务系统调用,接口使用简单方便,只需要简单的调用接口,传递相应的参数即可。
RPC方式调用,后续支持的方式有:
-
Dubbo(已实现)
-
brpc(预留支持)
-
grpc(预留支持)
-
Motan(预留支持)
-
Sofa(预留支持)
-
SpringCloud(预留支持)
-
SpringCloud Alibaba(预留支持)
消息体
以JSON数据格式参数 目前提供了http
协议。
-
body 业务消息体
-
delay 延时毫秒 距
createTime
的间隔毫秒数 -
id 任务ID 系统自动生成 任务创建成功返回
-
status 状态 默认不填写
-
topic 标题
-
subtopic 保留字段
-
ttl 保留字段
-
createTime 创建任务时间 非必填 系统默认
启动HTTP Rest服务
首先,从GitHub Clone项目到本地
git clone https://github.com/sunshinelyz/mykit-delay.git
然后进入mykit-delay框架目录。
cd mykit-delay
执行Maven命令
mvn clean package -Dmaven.test.skip=true
接下来,进入 mykit-delay-core
的 target
目录下,运行如下命令。
java -jar mykit-delay-core-xxx.jar
其中,xxx是版本号,以实际下载的版本号为准。
接下来,就可以调用HTTP Restful接口来使用mykit-delay框架了。
添加任务
/push
POST application/json
{“body”:“{hello world}”,“delay”:10000,“id”:“20”,“status”:0,“topic”:“ces”,“subtopic”:“”,ttl":12}
删除任务
删除任务 需要记录一个JobId
/delete?jobId=xxx
GET
恢复单个任务
用于任务错乱 脑裂情况 根据日志恢复任务
/reStoreJob?JobId=xxx
GET
恢复所有未完成的任务
根据日志恢复任务
/reStore?expire=true
GET
参数expire
表示是否需要恢复已过期还未执行的数据
清空队列数据
根据日志中未完成的数据清空队列中全部数据。清空之后 会删除缓存中的所有任务
/clearAll
GET
消息体
以JSON数据格式参数 目前提供了http
协议。
-
body 业务消息体
-
delay 延时毫秒 距
createTime
的间隔毫秒数 -
id 任务ID 系统自动生成 任务创建成功返回
-
status 状态 默认不填写
-
topic 标题
-
subtopic 保留字段
-
ttl 保留字段
-
createTime 创建任务时间 非必填 系统默认
启动Dubbo服务
首先,从GitHub Clone项目到本地
git clone https://github.com/sunshinelyz/mykit-delay.git
然后进入mykit-delay框架目录。
cd mykit-delay
执行Maven命令
mvn clean package -Dmaven.test.skip=true
接下来,进入 mykit-rpc-dubbo
模块下的 mykit-rpc-dubbo-server
服务 的 target
目录下,运行如下命令。
mykit-rpc-dubbo-server-xxx.jar
其中,xxx是版本号,以实际下载的版本号为准。
引入mykit-delay依赖
以Dubbo方式接入mykit-delay,需要引入mykit-delay的依赖,如下所示。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
总结
三个工作日收到了offer,头条面试体验还是很棒的,这次的头条面试好像每面技术都问了我算法,然后就是中间件、MySQL、Redis、Kafka、网络等等。
- 第一个是算法
关于算法,我觉得最好的是刷题,作死的刷的,多做多练习,加上自己的理解,还是比较容易拿下的。
而且,我貌似是将《算法刷题LeetCode中文版》、《算法的乐趣》大概都过了一遍,尤其是这本
《算法刷题LeetCode中文版》总共有15个章节:编程技巧、线性表、字符串、栈和队列、树、排序、查找、暴力枚举法、广度优先搜索、深度优先搜索、分治法、贪心法、动态规划、图、细节实现题
《算法的乐趣》共有23个章节:
- 第二个是Redis、MySQL、kafka(给大家看下我都有哪些复习笔记)
基本上都是面试真题解析、笔记和学习大纲图,感觉复习也就需要这些吧(个人意见)
- 第三个是网络(给大家看一本我之前得到的《JAVA核心知识整理》包括30个章节分类,这本283页的JAVA核心知识整理还是很不错的,一次性总结了30个分享的大知识点)
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
深度优先搜索、分治法、贪心法、动态规划、图、细节实现题**
[外链图片转存中…(img-9bVE9CqS-1712994808531)]
《算法的乐趣》共有23个章节:
[外链图片转存中…(img-wiNhbHmw-1712994808531)]
[外链图片转存中…(img-H5TwOtoy-1712994808532)]
- 第二个是Redis、MySQL、kafka(给大家看下我都有哪些复习笔记)
基本上都是面试真题解析、笔记和学习大纲图,感觉复习也就需要这些吧(个人意见)
[外链图片转存中…(img-B2rOCGkU-1712994808532)]
- 第三个是网络(给大家看一本我之前得到的《JAVA核心知识整理》包括30个章节分类,这本283页的JAVA核心知识整理还是很不错的,一次性总结了30个分享的大知识点)
[外链图片转存中…(img-hG2KHDHn-1712994808532)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!