在Netflix的平台上运行着许多的业务流程,这些流程的任务是通过异步编排进行驱动,现在我们要实现一个分布式延迟队列,这个延迟队列具有如下特点:
分布式 不用外部的锁机制 高并发 至少一次语义交付 不遵循严格的FIFO 延迟队列(消息在将来某个时间之前不会从队列中取出) 优先级
一、使用Dynomite和Redis构建队列 Dynomite是一种通用的实现,可以与许多不同的key-value存储引擎一起使用。目前它提供了对Redis序列化协议(RESP)和Memcached写协议的支持。我们选择Dynomite,是因为其具有性能,多数据中心复制和高可用性的特点。此外,Dynomite提供分片和可插拔的数据存储引擎,允许我们在数据需求增加垂直和水平扩展。 1、为什么选择Redis? 我们选择Redis作为构建队列的存储引擎:
Redis架构通过提供构建队列所需的数据结构很好地支持了队列设计,同时Redis的性能也非常优秀,具备低延迟的特性 Dynomite在Redis之上提供了高可用性、对等复制以及一致性等特性,用于构建分布式集群队列。
一个队列被存储为Redis的有序集合(ZADD和ZRANGE等操作),Redis使用分数对有序集合中的成员进行排序,当往队列中存储数据时,根据优先级和超时时间计算分数。 2、使用Redis实现数据的push和pop 对于每个队列,维护三组Redis数据结构:
包含队列元素和分数的有序集合 包含消息内容的Hash集合,其中key为消息ID。 包含客户端已经消费但尚未确认的消息有序集合,Un-ack集合。
PUSH
根据消息超时(延迟队列)和优先级计算得分 添加到队列的有序集合 将Message对象到Hash集合中,key是messageId。
POP
计算当前时间为最大分数。 获取分数在0和最大分数之间的消息。 将messageID添加到unack集合中,并从队列的有序集中删除这个messageID。 如果上一步成功,则根据messageID从Redis集合中检索消息。
ACK
从unack集合中删除messageID。 从Message有效集合中删除messageID。 客户端未进行确认的消息,会被再度推回到队列中(这是一个定时任务负责检测)。
3、可用分区和机架意识 我们的队列是在Dynomite的JAVA客户端Dyno之上建立的,Dyno为持久连接提供连接池,并且可以配置为拓扑感知,此外,Dyno为应用程序提供特定的本地机架(在AWS中,机架是一个区域,例如 us-east-1a、us-east-1b等),us-east-1a的客户端将连接到相同区域的Dynomite/Redis节点,除非该节点不可用,在这种情况下该客户端将进行故障转移。这个属性被用于通过区域划分队列。 分片 队列根据可用区域进行分片,将数据推送到队列时,通过轮训机制确定分片,这种机制可以确保所有分片的数据是平衡的,每个分片都代表Redis中的有序集合,有序集中的key是queueName和AVAILABILITY _ZONE的组合。 避免全局锁
每个节点(上图中的N1...Nn)与可用性区域具有关联性,并且与该区域中的redis服务器进行通信。 Dynomite / Redis节点一次只能提供一个请求,Dynomite可以允许数千个并发连接,但是请求是由Redis中的单个线程处理,这确保了当发出两个并发调用从队列轮询元素时,是由Redis服务器顺序执行,从而避免任何本地或分布式锁。 在发生故障转移的情况下,确保没有两个客户端连接从队列中获取相同的消息。
处理Un-ACK的消息 后台进程监视UNACK集合中的消息,这些消息在给定时间内未被客户端确认(每个队列可配置)。这些消息将移回到队列中。
感兴趣可以加Java架构师群获取Java工程化、高性能及分布式、高性能、深入浅出。高架构。性能调优、Spring,MyBatis,Netty源码分析和大数据等多个知识点高级进阶干货的直播免费学习权限 都是大牛带飞 让你少走很多的弯路的 群..号是:855801563 对了 小白勿进 最好是有开发经验
注:加群要求
1、具有工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加。
2、在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加。
3、如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加。
4、觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加。
5.阿里Java高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!