整理的OSChina第37期高手问答——消息队列服务,嘉宾为 @shaneyuan 。
@shaneyuan 现就职于广州 UC 公司,是 UCMQ 的作者,以下简称SY。
UCMQ是一款轻量的HTTP协议级消息队列服务组件,项目的最初原型来自 @张宴 的HTTPSQS。
基本特性:
- 支持标准的HTTP协议( GET/POST方法),支持长连接(keep-alive);
- 请求响应非常快速,入队列、出队列速度超过10000次/秒;
- 每个UCMQ实例支持多队列,队列通过操作接口自动创建;
- 单个队列默认限制存储100w未读消息,可以不限制(非必要建议限制);
- 可以在不停止服务的情况下便捷地修改单个队列的属性(大小限制/只读锁/延时队列/同步频率);
- 可以实时查看队列属性(入队列数量、出队列数量、未读消息数量、消息积压数量)。
- 每个队列有独立的数据文件易管理易搬迁。
消息队列简介及应用场景相关:
消息队列(Message Queue):把消息按照产生的次序加入队列,而由另外的处理程序/模块将其从队列中取出,并加以处理;从而形成了一个基本的消息队列。使用消息队列可以很好地将任务以异步的方式进行处理,或者进行数据传送和存储等。例如,当你频繁地向数据库中插入数据、频繁地向搜索引擎提交数据,就可采取消息队列来异步插入。另外,还可以将较慢/较复杂的处理逻辑、有并发数量限制的处理逻辑,通过消息队列放在后台处理。
常规的使用场景:短信服务、电子邮件服务、图片处理服务、好友动态推送服务等。
协议相关:
使用HTTP协议单纯考虑了跨语言/跨平台和易接入。我个人觉得UCMQ的性能不需要太过担忧,大家可以看相关测试数据:http://tech.uc.cn/?p=1344 前提是UCMQ只是一个单进程单线程的服务。如果实在对性能有极高要求可以部署多个实例。
周边方案对比:
1.UCMQ比起其它消息组件的长处和短处是什么。
SY:与其他消息队列相比,延续了:协议通用性好/性能高;扩展了:易用性/数据安全性高/内存消耗小(数据缓存随读写位置移动)/易搬迁(每个队列数据独立)/易维护(轻量级)/监控简单(可实时获取“所有/单独”队列状态信息)/添加了特色的队列服务(延时队列/队列写锁等)。
主要有价值的问答整理如下:
1、单个UCMQ无法满足性能要求怎么办?
SY:如果单个实例已经到达性能瓶颈,建议部署多个实例客户端已实现负载均衡机制(轮询或随机)。
2、一般消息队列里储存的数据格式是json吗? 消费消息的时候, 从队列中取出数据, 做相应的业务处理, 请问你们是使用crontab来做定时还是nohup呢?消费队列这块想多了解点。
SY:消息队列中的数据可以是任意格式,对于业务来说json是个不错的选择。消费者模块可以处理完后即时再去读取队列中的新消息,如果队列取空后服务端会返回特殊的标识,消费者模块通过识别该标识休眠读取线程,建议使用定期休眠机制(如:100ms)。
3、 任务分发策略,有订阅功能吗?
SY:UCMQ不支持订阅功能,业务不分发。相对于gearman UCMQ没有同步操作(即:生产者将消息写入队列后,队列将触发消费者来读取消息),在UCMQ中读写队列都是由客户端(包括:生产者和消费者)主动发起的,所以不是由消息队列分发。
4、发生异常时的处理流程是怎样?
SY:如果消息生产者成功的将消息写入队列后,该消息一直有效直到被消费者成功读取或者消息体被损坏。取出后的消息将不可再访问。
5、UCMQ是怎么减少IO消耗提高读写性能的?
SY:读写位置的数据都是缓存在内存中的,并随读写位置移动而移动。
6、如果不手工清理的情况下,数据量级变大后会不会对系统产生性能的影响?数据是如何进行清理的?
SY:后台数据存储是分文件存储的,已读完的数据文件将被清理,所以不会消耗存储资源。从存储设计(http://tech.uc.cn/?p=1344)了解到只缓存当前读和写的数据文件,性能不随数据量增大而下降的。
7、我曾短暂地使用过gearman的队列服务。1. 任务分发策略(如何选择worker)
简单读了一下您github上的代码,是不是说您的队列入队时,就是按先后入队,然后mgr去等待所有已经注册的work的请求,然后按请求顺序理出 队?或 是其它的算法策略?
如果work或mgr服务在运行中,出现异常,那异常前正在执行的任务将如何容错和重置?
3. 如何保证队列中的每一个任务,可以正常的执行完成
一般来说,您的见解是一个任务分发出去之后就被消费掉了(一次执行),如果执行时异常导至任务未能正常执行完,任务将消失?还是采用什么策略保 障任务消费是可以正常完成的?是由消息队列服务来监控保障还是采用日志处理方式,由开发者后期自行重置触发呢?
4. 您提到了,您的队列是记录在文件系统中的,我是否可以理解,是保存在了hash后的目录的文本文件中?如果队列任务是较大并发的项目或系统中, 是否会因为这块的IO瓶颈最后导致队列服务低效呢影响整体服务呢?如果存在这种可能性,您在设计时,是否有相应的解决方法呢?比如混合使用FS和 基于Ram的NoSQL或是自己实现一个基于内存的可持久化的存储形式。
SY:1:从MQ自身来说,出队列是按照入队列的先后顺序的--保证时序性是MQ的一个基本要求。
3:是的。当任务从MQ中取出后,其执行的正确性、完整性、安全性由取出者保证。
4:任何需要做持久化的产品,最终瓶颈都逃不过磁盘io的限制。我们能做的是,根据木桶原理,确保系统中不出线其它比磁盘io更短的短板。如果确实需要高性能的同时提供持久化和安全性的保障,那么可以考虑使用ssd硬盘--实测表明性能提升相当明显。至于纯内存的MQ,我们不排除后续版本中增加的可能性。但是混合使用纯内存和持久化的话,会使使用者无法确保当前到底用的是纯内存模式还是持久化模式--这样,在使用者看来,这样的MQ既无法时刻保证安全性,也无法时刻提供高性能,所以这样的MQ是不可信赖的(不可信赖的产品,在稍微重要的场合下,基本上就等于是不可用的)。