EQueue – 详细谈一下信息持久化以及消息堆积的宏图

前言

事先写了平首文章,总体介绍了EQueue。在圈这篇稿子之前要还不曾看了那么篇稿子,可能会见看无知情就首文章。所以建议未尝看罢之心上人要事先押一下那么篇文章被所涉及的各种概念,这样才会重好的明亮本文所说之情节。说实话我那会儿写EQueue也是获得在同等栽玩的情态的,就是想尝写一个分布式消息队列,用来也ENode提供分布式消息通信的力。后来形容在写在,发现更好打,因为看这行列以后当会死实用,所以就是花了重复多之岁月去规划它,完善它。希望它们说到底会于重复多之人数采取。到目前为止,我觉着眼前着力落实了以下特点:轻量级、分布式、高性能、消息而持久化、支持大气堆积消息(不为压内存大小)、支持消费者集群、消费者流控、消息的监控支持。本文自怀念重新要解析一下音之持久化以及信息堆积方面的计划。先是说明一下,这里的统筹还是自身个人的设计,没有参考成熟之音讯队列的做法,比如rabbitmq,
rocketmq,
kafka,等。我认为能够以自己之思路去贯彻一个著作,这种感觉确实好!接下我们初步分析吧。

EQueue核心架构简介

有关消息之持久化,我在第一首文章被其实已基本关系了,请看是链接。为了后面方便说明问题,我在这里又贴一下EQueue的着力概念图:

NoSQL 1

假如齐图所示,EQueue主要是因为三局部构成:1)Producer,即消息生产者;2)Broker,即存储消息之地方,上图被红框的一对;3)Consumer,即消息消费者。

信息的数据结构设计

齐图中之Broker我们好理解为同样宝服务器,该服务器即用来存储消息之。Producer发送消息是发到此服务器,Consumer消费信息吧是由之服务器将消息。Broker上的每个消息还产生Topic和Queue的概念。Topic与Queue的涉嫌是,一个Topic下可以产生差不多只Queue,QueueId用一个序号来分别。比如一个Topic下发出4独Queue,那立几个Queue的QueueId分别吗0,1,2,3。然后一个Producer发送消息时,它会按部就班有路由方式(ENode中会按照聚合根ID或CommandId的hashcode取模来路由至有特定的Queue)来拿信发送到Broker上目前Topic下之谁Queue。所以,在发送一个音讯不时,Producer除了会晤传递消息之始末外,还会传送消息的Topic以及QueueId来告诉Broker,这个信息是一旦放在何的。然后Broker根据Topic以及QueueId得到相应之Queue,就可以开始举行持久化消息的逻辑了。下面我们看一下一个持久化在Broker上的音信的数据结构:

    [Serializable]
    public class QueueMessage
    {
        /// <summary>消息所属Topic
        /// </summary>
        public string Topic { get; set; }
        /// <summary>消息内容,一个二进制数组
        /// </summary>
        public byte[] Body { get; set; }
        /// <summary>消息的全局序号
        /// </summary>
        public long MessageOffset { get; set; }
        /// <summary>消息所属的队列ID
        /// </summary>
        public int QueueId { get; set; }
        /// <summary>消息在所属队列的序号
        /// </summary>
        public long QueueOffset { get; set; }
        /// <summary>消息的存储时间
        /// </summary>
        public DateTime StoredTime { get; set; }
    }

MessageOffset是信息的大局序号,就是Broker上之信息的唯一ID,QueueOffset是该消息在Queue中之序号,是以拖欠Queue中唯一。其他的性质应该就甭多讲了。

起上面的数据结构可以见见,只要我们持久化了音,那如果消息不丢,那咱们得得依据这些信息重建起具有的Topic以及Queue,以及可理解消息于Queue中之序号与那全局序号的映射关系,因为消息我都曾包含了这映射关系了。

信息之持久化和堆的琢磨

为什么要持久化?因为咱们的音未可知弃,我当就一个理由就是够用了!那么怎么持久化?我能想到的方案有三单:1)写文件;2)存key/value的nosql,比如leveldb;3)存储在事关型db,比如Sql
Server;

至于前面两单方案的议论,在眼前无异篇稿子遭受发生于详细的讨论,本文不思量多讨论了。因为EQueue最终采取的是第三种植方案,也不怕是为此干型db来持久化,目前实现之凡Sql
Server。

摘Sql Server作为信息存储的权衡考虑

而是每个过来的信,都一直持久化到Sql
Server,那持久化会成为瓶颈。所以,在性质和可能扔消息里,我选了或者摒弃消息的方案。所以自己设计为定时持久化消息(就比如我们描绘副文件的内存,nosql或者操作系统还是发缓存的,并不曾立刻刷入磁盘一样!),现在凡各级隔500毫秒,使用SqlBulkCopy的法门批量持久化消息。大家懂得Sql
Server的SqlBulkCopy的属性是格外强之,据本人个人的测试,每秒20W肯定不是问题。所以,我可认为,SqlBulkCopy不见面化信息持久化的瓶颈。但是因为是定时持久化的。所以若服务器断电了,那咱们来或会见掉最近500毫秒的信。实际情形发生或有失的尚会再度多。因为如果Sql
Server有问题,导致信息还尚未道持久化,那断电的时节,我们少的就是不只有是500ms的信息了。那起道为?就是督查,我以为咱们可以通过对信息队列的监督,如果发现眼前就持久化的音讯之MessageOffset和脚下时髦的卓绝深MessageOffset之间的差值大于一定之警界值,就报警。这样咱们不怕能够立刻发觉消息的持久化是否发大气延缓,提早做出措施解决。好,通过SqlBulkCopy的定时持久化,消息持久化的习性瓶颈解决了。同时我们也懂了潜在的高风险与如何防范是风险了。另外一个保护措施是,我们得以被咱们的Broker服务器配置UPS电源,保证服务器断电时,还能够继承做事。

消费者拉取消息不时,从内存直接拉取还是于db拉取的权衡

苟,我们的信息都在内存,那消费者拉取性能肯定大高,因为当消费者如果抱并花费信息不时,它连接以内存,所以无会见时有发生IO,所以性能好。但是问题是,内存有限,放不下过多之信。假设一个音讯200字节,那16G的内存,最多只能放下8500W多单消息。这个数目显著要无敷高,因为我们的靶子是大方音之积聚,所以我们必须使做出一些衡量。我以为是不是可以如此,我们得安排一个阀值,比如1000W,只要当前Broker上即是的音讯数不顶1000W,那即便在内存;如果跨越1000W,则不再存放于内存,而是就存储在db。但是,好像要经过阀值来判定的话,好像还亟需开发者自己评估Broker服务器的内存大小以及平均每个消息之尺寸,从而才能够计算出一个靠边的阀值。能否让框架自动根据目前内存的使用量来评估是否延续之音可以放在内存也?之前自己哉是这想法,但是后来或利用了阀值的方案。因为后来贯彻的时刻,发现功能不好,而且由于信息消费后还会见让定时删除,且消息也以以不断追加,且我们以到的时服务器的可用内存有或无是那纯粹。总之,算法比较复杂,且无太平静。所以,最后要用了简约可靠的阀值方案。

那么这样的话,就是同有信息在内存,一部分勿在。那当我们拉取到无以内存的音信不时,那不是一旦去拜访db了?那消费者花信息性能不是碰头痛下跌了吗?我呢闹这担心,所以,想了只方式。就是当发现时如果花费的音信不在内存时,则一次性批量自db拉取N多消息,比如5000独(可配备)。拉取过来后,立马存储到内存。这样当顾客一旦花费就5000单信息时,我们会确保这些信一定在内存了。也就是说,最差之图景,假如现在具备的消息还不在内存,那咱们访问db的效率是,每5000独消息,去看同次等db。这样咱们得以大幅度的跌拉取消息的频率,从而基本无会见潜移默化消费者花信息之特性。另外你恐怕会见担心一次性从db拉取5000个信息可能会见比耗时,这点自己测试了产,性能还是老高之,肯定不见面化为瓶颈。因为咱们的音讯之主键就是信的全局序号,是一个long类型的价值,在db的消息表中就是是主键,根据主键用>=,
<=的口径去询问,性能是怪快的。

除此以外,实际上由此阀值是基于当前外存中还无为消费之消息数来判断的,只要我们的顾客性能及得及生产者发送信息的性质,那Broker上反驳及无会见产生大气积的消息。因为我们的消息而为立马消费了,那Broker上会有定时的线程,定时从Broker的内存移除已受所有消费者一度花的音信。这样Broker上即还无叫消费之消息数应该无会见到阀值。这样有的消息还得是于内存有的。只有当顾客的性能长时跟不上生产者的性时,才见面并发信息堆积,我们才见面启动阀值保护措施,将超阀值的音讯不再放入内存,以防止内存爆满,使机器挂掉。所以,我们得以预见,监控体系是多么重要,我们应当就关注监控数据,设置好报警规则,确保尽量吃信息都以内存,这是一个吓的实践。

透过地方的剖析,我们知晓了什么样管内存不见面被没花费的音信占据满之一个办法,接下我们来探视消息索引的问题。

要是消息的目录信息极多,内存放不产了为?

点来提到了,一个Topic下有多独Queue,每个Queue实际上就是一个逻辑队列,该队里存放了音信时在Queue中之岗位(序号)以及该消息的全局位置(序号)之间的投关系。简单的说,就是每个Queue中来一个ConcurrentDictionary<long,
long>,key就是queueOffset,value就是messageOffset。我管这个映射关系字典叫做消息之目信息。

经过前我们本着信息的数据结构的解析,我们解这些Queue我们是无论需持久化的,也就是说我们好置身内存。那内存真的放之下呢?经过自身的测试,我发现ConcurrentDictionary<long,
long>还是颇占内存的。每100M的内存测试下来只能加大100W只中等大小的信索引(long类型的key/value键值对)。这样的话,1G外存只能放1000W单左右的目录了,10G内存也只能放1亿只左右之目。太少了!那怎么收拾为?思路是,既然放不生,那即便内存为不放开了。我思想后意识,其实我们决不把每个消息的目录都坐落Queue里,我们实际上要知道当前Queue的手上最为要命的QueueOffset即可。

接下来,任何一个顾客NoSQL花信息时,都是面向单个Queue的,EQueue采用的是关模型(Pull
Message),消费者每次过来拉音还是关一批去消费,现在默认值是32单。所以,假如当前Queue的太深QueueOffset是100,然后消费者发过来的拉取消息的要被只要拉扯取之起始消息的QueueOffset是50,然后一旦现在Queue里的第50只初步交100只次的有所消息所以还无在内存。那怎么处置也?很简短,我们好在这,用同一长达SQL到Sql
Server中之消息表中批量拉取一定数量的信索引(比如5000(可安排)个,实际可能不得不拉取到50单,因为目前这个Queue最可怜之Offset只出100),然后拿这些拉取到的目录设置到Queue上,这样是Queue上就是生出50交100之这些信息的目录信息了。这样咱们就能明了从50至81(共32独目录)之间的这些信息之大局序号了,从而就能够以到最后之信息了,然后就是会回给买主了。由于此处我们为是批量拉取消息索引,所以和前一样,也不见面时有发生啊性质问题。

这边,因为此地要根据Topic, QueueId,
QueueOffset这几只尺码由消息表中询问信息,所以一旦无行使Sql
Server这种干项目数据库,还确实不好实现。因为如果用文件持久化消息还是用key/value的nosql,虽然持久化性能特别高,都足以马上持久化(实际上为尚未那好,呵呵,因为NoSQL也未是立即刷盘的啊!断电后为起撇下数据的高风险),但还无支持像这种需要因此到二级索引的询问需要。所以,这也是自我赞成被考虑使用关系项目db的缘由。另外,为了查询时性上极端美,我本着这三个字段建立了目录,确保不见面全表扫描,提高查询性能。

实际上,我此吧被Queue可以于内存缓存多少只消息索引设计了一个阀值,默认是500W(大家可因实际情况和Queue的多少来布局,以后EQueue会考虑让不同Topic下的Queue支持配置不同的阀值)。也就是说,只要Queue中之消息索引不跳500W,那有索引都在内存,只有过了500W,才未见面重新把消息索引放在内存。同样,因为要是消息给消费就的话,Queue中的消息索引都见面叫立马移除,这样Queue中之信索引一般就是无容许超越500W了。只有消费者花信息之快增长日子低于生信息的快慢,才会产出Queue中之消息索引出现堆积最终超过500W的情况。同理,我们这边而做好监督,那吧能够保证不见面到阀值。

吓了,Broker上顶占用内存的2个点我们且分析了如何支配内存的占用大小。总体思路是通过控制内存中缓存的消息数以及消息的索引数来齐内存不会见以消息及信息索引的无休止长而造成用了。然后以内存中信息还是消息索引不存在时时(监控做的口舌的口舌,这种情况相似不见面发生),通过批量打db快速拉取(两种植拉取都是可走索引)再放入内存的法门,来实现消费者拉取消息时,依然能够维持高性能。

信息之督察规划

通过地方的分析,我们了解,我们蛮需要掌握,当前Broker上的音信堆积情况。当出现有堆积如山时,我们若赶早做出处理。所以,我实现了极中心的督查数据的展示。主要实现了点儿独页面:

1)展示时Broker上出怎么样Queue,每个Queue的此时此刻Offset,当前已经为有着顾客花之尽可怜Offset,Queue中之目前消息数。如下如所示:

NoSQL 2

2)展示时Broker上每个Queue被消费之景,每个Queue正在让谁消费者花,已经为此消费者花及哪了(也尽管是花位置)。如下图所示:

NoSQL 3

切切实实的数码,大家可到http://www.enode.me/equeueadmin这监控页面查看。上面的监察数据还仅是太基础之,但为是极其重点的数量。以后我会不断丰富监控数据与长报警功能。

ps:
http://www.enode.me是为此ENode实现之一个简练论坛,以上这个监控页面的地点则是本着之论坛的信监控页面。

 

以急匆匆2沾了,就到立刻吧!又获得一致篇,开心,呵呵。

网站地图xml地图