消息队列
应用场景
有很多业务, 客户端和内网都要进行数据传输和交换, 现有架构中, 客户端不能直接访问内网,
那么客户端只能: 先把数据保存到外网服务器, 然后内网服务器再拉回来处理. 这种方式可以保证数据
都能被处理, 但实效性不够.
通常, 外网服务器只起到一个暂时保存数据的作用, 保存客户端报上来的数据, 然后等待内网来拉走,
把客户端看做producer, 内网看做consumer, 这正是消息队列的用武之地.
客户端先把数据写入外网服务器的消息队列, 然后内网服务器再从消息队列取走数据, 消息队列须满足:
(1) 支持高并发的入队和出队操作, 允许很多客户端同时插入数据, 而且允许内网服务器高频率地取走
数据
(2) 支持数据的持久化, 为保证速度, 消息队列缓存在内存中, 如果内存不够用了, 则写入磁盘.
(3) 支持一次性插入多条记录, 以及一次性取走多条数据, 这样可以提高传输效率
二 技术选型
1 存储方案: Tokyo Cabinet
Tokyo Cabinet数据库是日本最大的社交网站mixi开发的一款Key-Value数据库,之所以选择Tokyo Cabinet,
而不是MySQL, Redis或者Memcached, 这是因为:
(1) Tokyo Cabinet的读写速度非常快, 比MySQL快很多, 和Memcached差不多, 比Redis当然慢一截,
有测试数据为证:
写入100万条:tcbtest write test.tcb 1000000
时间: 0.994秒 速度:100,6036条/秒
写入200万条:tcbtest write test.tcb 2000000
时间: 2.028秒 速度: 98,6193条/秒
写入500万条:tcbtest write test.tcb 5000000
时间: 5.276秒 速度: 94,7687条/
(2) Tokyo Cabinet占用内存不大, 而且支持数据的持久化, 用户可以设定内存缓存的大小, 缓存不够用
的时候, 就把数据持久化到磁盘
2 网络接口: Libevent
Tokyo Cabinet只是一个数据存储层面的东西, 它没有提供网络接口, 所以得写一个http服务器为用户
提供服务.对于高并发的服务器来说, 基于事件驱动的libevent网络库是非常好的选择. 事实上, libevent
自带了一个简单高效的http服务器实现, 对于消息队列服务器来说足够使用了. 代码不足400行.
三 如何使用
用户使用http的get请求来操作消息队列. 参数如下
o: 操作参数, 取值为{get|set|status}, set表示入队,get表示出队, status查看队列的状态
m: 消息数据.
p: 密码参数或者校验参数
n: 一次入队n条消息, 或者出队n条消息
1 入队
http://localhost:3333/dsr?o=set&d=foobar|hello|world
把foobar, hello, world三条消息插入队列,消息之间用"|"号隔开,若成功入队, 服务端返回0#0
2 出队
http://localhost:3333/dsr?o=get&n=10
从队列中取出10条消息, 每条消息以换行符隔开.
3 状态
http://localhost:3333/dsr?o=status
查看队列的状态,显示队列的容量, 当前消息数量, 队列头指针, 队列尾指针:
四 压力测试
测试环境 : 8核CPU
1 入队操作
1000并发量, 插入10万条消息, 每条消息512字节
* 使用keep-alive
测试结果:21246 qps, 占用磁盘空间: 51M
* 不使用keep-alive
测试结果:12768 qps, 占用磁盘空间: 51M
2 出队操作
1000并发量, 每次取走一条消息, 取10万次
* 使用keep-alive
测试结果: 27709 qps
* 不使用keep-alive
测试结果: 11461 qps
从测试结果来看, 消息队列的读写性能都非常不错, 应该能够满足很多应用的需求