Blog:http://blog.csdn.net/cenwenchu79/问题小丹同学在旺旺上问我是否可以用Memcached实现简易消息中间件类似的功能。觉得这个需求很奇怪,就问了一下具体的应用场景,然后小丹就上来和我具体的谈了究竟需求是什么。其实小丹的应用场景是这样的:客户需要分析一些业务数据,但" />

技术方案的讨论过程来看化繁为简

系统 1503 0

Author: 文初 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

Blog: http://blog.csdn.net/cenwenchu79/

问题

小丹同学在旺旺上问我是否可以用 Memcached 实现简易消息中间件类似的功能。觉得这个需求很奇怪,就问了一下具体的应用场景,然后小丹就上来和我具体的谈了究竟需求是什么。其实小丹的应用场景是这样的:客户需要分析一些业务数据,但是业务数据又是很庞大的,在原有系统每天晚上都有一次日分析,将业务数据分析并且归档,但是如果要产生即时分析的效果,用原有系统无法实现,因为当天的数据内容没有被分析,同时如果即时的去分析并且累加到历史分析数据上,性能也不能满足需求,因此考虑通过消息机制来实现异步分析,至于异步处理的时间容忍度,可以通过配置来实现,同时希望异步分析是可线性扩展的,支持集群,提高效率。为什么不直接使用中间件呢?高并发的稳定性,维护的成本,性能要求,使用成本,这些直接就排出了直接去使用中间件的想法。

起始方案的讨论

在回到小丹最初提到是否可以通过 Memcached 来实现类似于简易消息中间件的问题上来。首先是否将消息队列作为一个对象保存在 Memcached 中,这种做法明显不支持高并发的情况,因为 Cache 本身的 get,put 无法保证事务。在 Memcached 中只有计数器是支持高并发的操作,因此考虑是否使用计数器并且按照一定规则来生成 key ,通过对计数器的增减来让不同消费者获取到不同的消息,这种机制最大的问题在于: 1. 轮询的压力不小(小丹希望是订阅者模式, Push 过去而不是 Pull )。 2. 计数器增减不论怎么做都实现的是栈而不是队列。那么是否使用我扩展的 Memcached KeySet ,这点我自己就反对了,这个功能效率很低,而且对于 Memcached 本身在高并发下操作是否有影响还不得而知。问题越绕越走向死胡同了。

方案的转变

转换思路,重新分析小丹的需求,究竟哪几点是他真实需要的: 1. 通过消息方式解耦 Web 应用和业务分析处理。 2. 消息必须较为及时的传递到业务分析模块。 3. 业务分析模块需要支持集群方式线性扩展性能。实现这些需求真的需要简单的消息中间件或者集中式存储么?看看下图的结构:

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="图片_x0020_1" style="VISIBILITY: visible; WIDTH: 277.5pt; HEIGHT: 286.5pt; mso-wrap-style: square" type="#_x0000_t75" o:spid="_x0000_i1026"><imagedata o:title="" src="file:///C:/DOCUME~1/WENCHU~1.CEN/LOCALS~1/Temp/msohtmlclip1/01/clip_image001.emz"></imagedata></shape>

技术方案的讨论过程来看化繁为简

从图上可以看出这么几个问题: 1. 消息中间件本身处于单点,如果需要扩展或者消息本地化增加了复杂度。 2. 对于消息的获取是采用 push 还是 pull ,如果是 push 那么需要中间件支持订阅者的维护,如果是 pull ,则需要考虑并发以及性能问题。 3. 消息的即时性,这个还是依赖于消息中间件的实现机制。总的来说,如果要通过集中式缓存方式实现消息中间件的简单功能,还是有很多问题。那是否直接使用消息中间件的第三方支持呢,其实又回到了最初提出的不使用的缘由。这么设计是否太复杂呢?

回过头来看看 Memcached 的使用情况,突然发现其实事情可以简单来说,我记得写过一些说明来解释为什么我说 Memcached 是集中式缓存而不是分布式缓存,其实是客户端的分发算法让很多人觉得好像分布了数据和可无限扩展。其实这种技术结合 Hadoop HDFS 的部分设计思路,可以给出一个比较好的解决方案。看看下图的结构设计:

技术方案的讨论过程来看化繁为简

<shape id="图片_x0020_3" style="VISIBILITY: visible; WIDTH: 415.5pt; HEIGHT: 302.25pt; mso-wrap-style: square" type="#_x0000_t75" o:spid="_x0000_i1025"><imagedata o:title="" src="file:///C:/DOCUME~1/WENCHU~1.CEN/LOCALS~1/Temp/msohtmlclip1/01/clip_image002.emz"></imagedata></shape>

上图去掉了消息中间件的角色,增加了 Asyn Processor Manager 的角色,但是此角色也可以去掉,更为简化的实现需求,增加 Asyn Processor Manager 的功能仅仅是为了提供动态增减 Asyn Processor 的功能。具体说一下流程:

1. Web 应用启动时,读取本地配置获取 Asyn Processor 列表载入内存,同时根据 Asyn Processor Manager 的配置去发起请求获取 Asyn Processor 最新的可用列表(如果无法获取,则以本地的为准)。

2. Web 应用根据本地实现的分发算法(最简单就是采用 key hash ),来选择 Asyn Processor ,发送请求处理的消息。

3. 如果 Asyn Processor Manager 不存在, Web 应用也可以实现定时发起 query status 请求来确认 Asyn Processor 的存活状态,并且更新,保证消息的正常发送。如果 Asyn Processor Manager 存在,那么确认 Asyn Processor 状态是否存活可以由 Asyn Processor Manager 来做( Push 或者 Pull ),而 Web 应用则可以使用对 Asyn Processor Manager 的定时查询来获得最新的 Asyn Processor 列表。

4. Asyn Processor Manager 可以提供增加和删除 Asyn Processor 的接口,这样就可以支持 Asyn Processor 的增加和删除,但也正因为 Asyn Processor Manager 的单点易于注册和管理 Asyn Processor ,也增加了单点的风险,因此每一台 Web 应用需要对 Asyn Processor Manager 不可用作好本地化配置的后备策略。

5. 使用 Http 协议作为消息传输协议,这样避免 SA 去维护端口的麻烦,同时也能够充分利用 REST 的方式来完成业务逻辑( Options 方法可以用于心跳, Put Delete 可以用于 Processor 的增减(设置 Http Head 认证方式即可解决安全问题), Get 方式获取信息( xml,json 等等格式可以很容易处理))。

上面的方案可以看出,如果去掉 Asyn Processor Manager ,其实方案很简化,就是每一个客户端有一层类似于 Memcached 客户端的分发机制,同时比 Memcached 免去了对于连接池维护的复杂性,仅仅只需要维护状态标示即可。

最后还嘱咐小丹对于 Asyn Processor 的设计需要合理化,这部分需要支持消息接受和处理的并行处理,提高 Asyn Processor 的处理能力,同时通过分页批量处理消息的方式减少对于 DB 的压力(当然需要根据具体的时效性设置消息页的大小以及消息页 Flush 的时间)。

后话

上面的方案可能不是最好或者最优的,这里仅仅只是分享一下自己解决这个问题的一些心得。这此的方案讨论也走了一些弯路,有时候在做任何选择以前首先需要考虑的是到底自己需求是什么,然后再去考虑选择什么技术去实现。同时尽量还是那句老话 ”Make it Simple” ,做技术的人总是喜欢做的很复杂,功能很强大,但是最后迷失了最初的目标,忙于去完善那些 80% 没有用的功能,却没有去做好那 20% 客户最 Care 的功能。化繁为简,见招拆招,才能四量拨千斤。

技术方案的讨论过程来看化繁为简


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论