基于leveldb的持久消息队列SDK

栏目: 数据库 · 发布时间: 6年前

内容简介:最近看技术博客,谈到他们开发了一种日志采集的agent部署在各个服务器上,由业务直接通过unix socket实时发送日志给agent的场景。在agent里他们使用了持久化的本地消息队列用于缓冲日志数据,这样可以缓冲因为日志服务端阻塞导致的日志堆积暴涨,以及避免agent宕机后的日志丢失问题。那么如何实现一个单机消息队列呢?自己实现一个可靠的存储系统是困难的,所以尽量不要造轮子,这里可以选择leveldb作为持久化介质,他是一个高性能的K/V存储SDK,写性能尤为突出。

最近看技术博客,谈到他们开发了一种日志采集的agent部署在各个服务器上,由业务直接通过unix socket实时发送日志给agent的场景。

在agent里他们使用了持久化的本地消息队列用于缓冲日志数据,这样可以缓冲因为日志服务端阻塞导致的日志堆积暴涨,以及避免agent宕机后的日志丢失问题。

那么如何实现一个单机消息队列呢?自己实现一个可靠的存储系统是困难的,所以尽量不要造轮子,这里可以选择leveldb作为持久化介质,他是一个高性能的K/V存储SDK,写性能尤为突出。

我实测了一下leveldb,顺序写大概30-40万的/秒(key有序递增),顺序读大概80-100万/秒,可以参考官方的 测试数据

实现思路

队列天生就是一个顺序读写的模型,在leveldb的K/V模型上构造出队列模型,需要一个队列的head头和tail尾2个指针,其中head表示写入的位置,tail表示读取的位置,初始都为0。

当push一条数据时,以head为key插入到leveldb,并让head=head+1,head自身同样需要保存到leveldb中进行备份。

当pop一条数据时,首先判断tail<head则说明有数据可读,那么以tail为key读取leveldb得到value,然后从leveldb中删除key=tail,并令tail=tail+1,tail自身同样需要保存到leveldb中进行备份。

考虑一下异常是否可以容忍:

  • push完成了插入,但是更新后的head没来得及保存leveldb。 — 重启后push的第一条消息会覆盖到head位置,丢失了一条消息。
  • pop删除了tail,但是更新后的tail没来得及保存到leveldb。 — 重启后的第一次pop查不到value,丢失了一条消息。

上述2个问题需要额外的日志机制保障可靠(redo/undo),本身也是一个麻烦的工作,好在日志业务还是可以容忍这点数据丢失的,再者agent的稳定性一般很高,不会频繁出现这种情况。

Golang的一个Demo

我一开始采用Golang写了一个Demo,后来测试发现性能太差劲,写入性能大概只有5万/秒,读取也就是2-3万/秒,与C++版本相差甚远。

这主要是因为Golang没有特别成熟的leveldb原生(golang开发)实现,而靠谱的唯有一个基于cgo技术封装了c++的libleveldb,所以我选择了它。

因为队列压测时每秒有几十万的请求量,这种频繁的在golang和C之间的调用切换成本极高,所以导致性能不可思议的低下。

这个Golang的Demo作为一个SDK包存在,实现了一个GoQueue类,大家有兴趣可以了解一下代码:

GoQueue


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

物联网导论(第2版)

物联网导论(第2版)

刘云浩 / 科学出版社 / 2013-8 / 45.00元

物联网是一个基于互联网、传统电信网等信息承载体,让所有能够被独立寻址的普通物理对象实现互联互通的网络。它具有普通对象设备化、自治终端互联化和普适服务智能化三个重要特征。 《物联网工程专业系列教材:物联网导论(第2版)》从物联网的感知识别层、网络构建层、管理服务层和综合应用层这四层分别进行阐述,深入浅出地为读者拨开萦绕于物联网这个概念的重重迷雾,引领求知者渐渐步入物联网世界,帮助探索者把握第三......一起来看看 《物联网导论(第2版)》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具