前言:
闲来无事,加工作不饱和,饱思淫欲的状态下,用golang实现了一个基于redis通信协议的pubsub通信服务端. 这个轮子实现的还很粗暴,内部实现主要用的是golang channel ,不仅可以高效的控制并发读写,而且可以跟tcp连接关联做事件通知。 至于持久化部分还没写完,我现在选用的是第一个方案。 该代码实现上还是比较简单,还是需要大把时间去打磨。
该文章后续会有更新, 原文地址: http://xiaorui.cc/?p=4847
语言方面的选择?
我熟练的语言不多,最熟练的Python实在是写腻味了,再说Python也不适合写这类带有存储性质的服务端。openresty lua 更适合写http相关的逻辑。 最后只有Golang了… 近一年来,我大多数时间都在写Golang,熟练程度不下于Python了,只是没有更多的涉及源码实现上。
协议方面的选择?
选择redis protocol 作为通信协议的原因很简单,redis通信协议本身很是简单高效,虽然比不上thrift、protocol buffer的性能和表现力,但好在方便调试。另外,我不需要开发各个语言的协议库包,直接使用各语言的redis sdk就可以了,还附赠一个redis-cli 及redis-benchmark工具。
持久化方面的几个选择?
第一种,像 redis 日志方式看似简单,但后面日志过大后肯定是需要rewrite。 那,这就有些棘手了,golang上层没有很好的fork机制,不能进行copy on write。 不能cow那就不能容易的保证状态的一致性。 那么我需要自己去compact 日志,进行合并收敛。
第二种,使用rocksdb来实现数据的存储,简单高效… 在golang channel内存只流传 数据id,这样不管有多少个queue,只会有一条数据在库中,极大的节省了空间。
第三种,像kafka那样,数据分区概念,逻辑分区是对应磁盘目录的,每个目录里都有的一堆的有序的segment数据和索引. 对于客户端来说,可以直接访问,也可以用逻辑id来访问。 这样的做法,不仅能方便的实现消息确认,而且可以做数据的历史回溯。 但是对于我来说,开发量有点大呀…
go_pubsub项目代码放到github上了,有兴趣的可以看看. https://github.com/rfyiamcool/go_pubsub
下面来演示下go_pubsub服务:
启动 server 端:
go run cmd/main.go
client端我们可以直接用redis相关的客户端和库包。
[gopy@xiaorui ~ ]$ redis-cli -p 9999 # AUTH 127.0.0.1:9999> auth your_password # 添加topic 127.0.0.1:9999> create topic xiaorui.cc # 绑定topic和queue_name的关系 127.0.0.1:9999> bind xiaorui.cc queue1 # 给topic为xiaorui.cc发送 hello 信息 127.0.0.1:9999> PUBLISH xiaorui.cc hello OK # 接收信息 127.0.0.1:9999> SUBSCRIBE xiaorui.cc queue1 Reading messages... (press Ctrl-C to quit) hello
END.