该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2011-08-11
最后修改:2011-08-11
最近一直比较忙,前面设计的架构完成了基本的实现,最近工作重心发生了点转变,偷闲来继续前面的话题;
那么有没有一种更高效的方式呢?
答案是肯定的,但那可能要进一步降低可靠性!
看看Facebook的Scribe日志收集系统的原理:
如果Scribe Server正常工作,Scribe Client将App的日志(可以看成一个消息)推送到Scribe Server端,如果不正常,则写到本地文件,当Scribe Server恢复正常时再将其推送过去;这里使用本地文件作为缓冲,那么能否综合Scribe和Kafka的优点来设计一个消息系统(或日志收集系统,改造一下可以互用),看下面的方案: 上面的MQ暂且叫他FastMQ吧,①中消息发布端直接写本地文件,同时消息订阅者通过Zookeeper协调,向相关消息发布者的Agent拉消息,并在本地记录消息指针状态; 如果嫌在消息发布端开启MQ Agent麻烦,那么如②中消息拉取协议使用SCP或FTP协议,用这些Linux必备的协议提供者作为Agent减少开发和部署的难度,在服务订阅端解析这些协议流,反序列化为消息供业务使用; 如果觉得消息只存储在消息发布端的磁盘不可靠,那么如③中可以在消息订阅者处理不及消息的时候,把消息数据缓冲在消息订阅端的磁盘上来备份数据,不过这样做就使系统变的复杂,虽然提高了可靠性,但是速度就会有所降低;
此种方案可以使消息分散的存储在业务本身的磁盘上,避免集中存储相互影响的缺点,同时又可以有效利用业务机器的磁盘(大部分业务机器磁盘基本没使用),另外还可以减少一次网络通信的过程,使从发送到接收的速度更快;但其本身也有不少缺点,要做好监控,避免消息大量积压的时候业务磁盘过度使用,对业务造成影响。
目前我们的监控日志收集系统使用的是和②中类似的方案,消息系统使用的是3方案,后期可能会将可靠性要求高的向1方案过度,可靠性要求不高的向最下面介绍这种过度!
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-08-11
消息传输分点对点模式和发布订阅模式,前者是1:1,后者是1:N,系统集成中主要应用的是1:1模式。这里使用发布者/订阅者的概念并不恰当。
业务逻辑的可靠性和消息传输系统的可靠性不能等同,传统的JMS兼容的MQ产品,包括ActiveMQ,甚至是IBM的WebSphere MQ 的所谓可靠性也并不能满足金融业务对可靠性的要求。消息传输系统不是数据存储系统,就算是有了持久化和事务的支持也不意味着它有多可靠,尤其是在集群环境下的大规模应用。消息系统是异构的、异步的、跨网络的,总不能把发送端和接收端做到一个分布式事务里。消息的丢失、重复、和非正常的延时都应该被看做是一种常态。 要保证可靠性应该在两端下功夫,毕竟数据库系统能提供的可靠性远比任何传输系统的可靠性要高得多。 在保证基本的系统稳定性的情况下,尽量提高传输性能和响应时间,通过三次交互来完成一次交易的可靠性远比依赖传输系统的可靠性用一次交互来完成同一交易要可靠得多。 我对MQ产品接触得比较多,千万不要以为把消息成功发送到MQ上就万事大吉。举个例子:如果在接收方的集群环境中某个节点出现异常,消息可能会丢失,也可能在该节点恢复后由于其持久化存储,该消息被恢复,从而造成不确定的延迟、也有可能在异常瞬间该消息被重新派发到其他路由节点,从而造成消息重复。 我的意思是说要保证应用逻辑的可靠性不要去依赖消息系统的可靠性,不是说MQ产品的那些保证可靠性的机制没有意义。 |
|
返回顶楼 | |
发表时间:2011-08-11
你说的有道理,我这里消息的发布订阅是广义的,可以理解为消息的生产者和消费者,在我的想法里,始终觉得queue应该是一个特殊的topic;
消息的可靠性保证确实需要整个生态系统来保证,但我们这里只讨论MQ的可靠性,MQ一样可以做到非常高的可靠性,在1方案中有很多手段可以用,你也可以进行二次提交,一旦提交成功将在多分存储设备上存储,这样首先保证消息不丢失,然后再通过一些列的发生操作保证消息一定能够发送成功,记录状态,如果一直发生不成功的可以人工干预,但这样势必影响速度,我上面的几个方案是根据不同的需求来选择不同的方案,互联网除了电子商务这块,一般的web2.0对可靠性要求没那么高,但数据是海量的,对处理的效率就有比较高的要求,这样就要牺牲一点可靠性了。 一次交互如果能满足可靠的需求的话,获得的高效率将是一个很好的回报! |
|
返回顶楼 | |
发表时间:2011-08-11
tcp保证不了数据库级事务的可靠,数据库的日志一样保证不了业务级的可靠
前向日志和日志要记录事务成功的提交标记,业务层要保证可靠最终还得自己实现这么一套东西,不可能单独靠下层的保障机制就可以 除非业务力度和数据库事务力度和划分完全一致 文件系统,数据库都有log机制来保障,但都只能加强本层的可靠,无法实现上层的可靠 但是显然数据库应该建立在tcp,而事务架在数据库上,这些会让事情更简单,上层实现下层的可靠成本巨大,没人会用udp做可靠的应用层协议 消息栈或者说实现某种有序列化安全保障的异步机制使用db应该说是实现成本最低的,唯一的问题在于扩缩上,即使使用提供分布式的nosql,也会在转发节点遇到瓶颈 这些分布式系统,实际上传输从来不是问题和麻烦所在,而是最大限度满足写、读的视图强一致性和事务、扩缩的平衡 |
|
返回顶楼 | |
发表时间:2011-08-11
这里不是要保证生产者、MQ和消费者一整套的事务,用MQ的目的就是解耦,如果做多方事务的话那就失去了意义;另外MQ也不应该保证多个提交消息的事务问题,它的处理规则是一条消息的可靠性;
MQ的可靠是只能保证数据的最终一致,而不能保证数据的强实时一致,它可以做到如果你提交给我成功(这个是否成功的通知可以通过同步,也可以通过异步),那么我一定给你最终发送成功,但我不能保证你可以立刻就获得一致的数据; |
|
返回顶楼 | |
发表时间:2011-08-11
redis全部存在内存中,应该不会比第1,2种方案慢吧?
除非第一二种方案不是分布式的,全部走内部内存,不经过网络。 |
|
返回顶楼 | |
发表时间:2011-08-11
akandfxs 写道 redis全部存在内存中,应该不会比第1,2种方案慢吧? 除非第一二种方案不是分布式的,全部走内部内存,不经过网络。 MQ天生不太适合用 nosql做存储。 内存型的nosql,快不过同一jvm内的内存。越追求性能,越丢了MQ最重要的可靠性。 |
|
返回顶楼 | |
发表时间:2011-08-11
实例化文件其实也是一种持久化的方案,消息发送出去后,并不一定意味着成功,我觉得可以设计成如果需要可靠性,则提供回查接口,保证消息的最终可靠性。对于不要求可靠的消息,则直接投递即可。本身就有一定的容错性。感觉1,2点主要是将服务端主动推送改成了订阅端主动找发布端拉取消息而已,而投递消息这个过程并不会产生多大的延迟。主动拉取消息并不是最优的方案
|
|
返回顶楼 | |
发表时间:2011-08-11
akandfxs 写道 redis全部存在内存中,应该不会比第1,2种方案慢吧?
除非第一二种方案不是分布式的,全部走内部内存,不经过网络。 我的意思是如果作为一个DB看Redis的话不仅仅是内存,还要有持久化,甚至还要有master-slave结构,这样才能一定程度保证可靠性,如果完全用内存那可靠性就太差了,一般应用不太能接受;最起码也要Snapshotting持久! 这样就引起一系列问题了! |
|
返回顶楼 | |
发表时间:2011-08-11
cdredfox 写道 实例化文件其实也是一种持久化的方案,消息发送出去后,并不一定意味着成功,我觉得可以设计成如果需要可靠性,则提供回查接口,保证消息的最终可靠性。对于不要求可靠的消息,则直接投递即可。本身就有一定的容错性。感觉1,2点主要是将服务端主动推送改成了订阅端主动找发布端拉取消息而已,而投递消息这个过程并不会产生多大的延迟。主动拉取消息并不是最优的方案
投递那一瞬间确实不会花太多时间,但在投递前和投递中要做一些列的可靠性措施,比如备份消息,尽可能减少主备之间消息的不一致发生,消息的状态记录,状态的同步,失败消息的重复发送,如果不是顺序消息的话需要有随机存储和查询的机制,很多很多,最终将导致发送速度慢下来! |
|
返回顶楼 | |