c++服务器应用zeromq和lua的设计问题

c++服务器应用zeromq和lua的设计问题,第1张

lua本身就是用标准C编写的,它的优点是小巧和灵活,而且又是动态语言,是解释执行的,所以适合用在游戏和一些嵌入式环境里。至于你上面所说的动态弱类型,垃圾收集,函数式编程,闭包等等,需要你至少读完一本lua书籍(ProgramminginLua)才能有个大概的了解,这些概念都不是一蹴而就的,需要不断的积累。

很早就听说了zeromq 这个项目,当时不太在意.后来同事kasicass 对这个项目做了研究和分享 ,开始重视起这个项目来.1) libevent封装了对网络I/O,信号,定时器等的处理,可以基于它之上做网络层的开发.2) ACE封装了不同平台下的系统调用,也提供好几种网络编程的模型.然而,zeromq不是libevent,也不是ACE,因为它的主要特性是:面向消息进行通信.所以,它提供的是比libevent,ACE处在网络通信中更高一层的组件.使用它,程序员不再需要上面提到的libevent,ACE之类的库需要关心的东西,程序员如果要使用zeromq,只需要做如下的事情:1) 告知所使用的patten,比如request-reply,pub-sub,push-pull等(下面会详细解释这个pattern).2) 告知是用于机器之间,还是进程之间,线程之间的通信.然后,将所需要发送的数据封装到zeromq自带的msg结构体中发送出去,使用者自己关心如何序列化/反序列化这些数据,然后如何处理这些数据就是使用者的事情了.这样看上来,使用者要关注的事情”高”了一层,大部分的精力都可以放在业务逻辑之上了.简而言之,它让使用者的精力放在了通信模式和业务逻辑上,而不是更下面一层的网络层上.下面解释一下zeromq常用的几种网络pattern:1) request-reply就是一般的C/S架构中,client与server之间一问一答的通信模式,比如最经典的echo服务.需要注意的是,client发送一个request,server必须有一个回应.server端作为publish端,而任何连接到服务端的client都会成为subscribe端.也就是说,server端会把当前的所有需要publish出去的消息全部发送到当前连接上去的client上.3) push-pullserver端作为push端,而client端作为pull端.如果有多个client端同时连接到这个server,则服务器会在内部做一个负载均衡,采用平均分配的算法,将所有的消息均衡发布到client端上.看上去,很稀松平常?接下来亮点真的来了.考虑如下一种场景.一个server端做为一组服务器集群最上层的一个proxy,起到负载均衡的作用,将请求按照它下面对应服务器集群依次派发到不同的 client端进行处理.某个时刻可能处理的机器只有2台,而随着负载越来越大,可能需要3台机器了,这个时候如果使用zeromq的push-pull 搭建的proxy端,则可以不用对之前搭建的server,client端进行停机,只需要新启动一个client连接上去,proxy层就会自动根据当前的机器分配平均派发任务了.cool.实际上,这些模式并不是什么新东西,只不过zeromq为使用者做了一个封装,而不是像libevent,ACE等还局限在网络层部分的封装,它关注的是通信层,通信模式等.个人感觉,zeromq部分解决 了erlang所要解决的问题:在多台机器中通信,派发任务等,是分布式通信的利器,但是局限于语言的限制,它没有办法做的跟erlang一样的完善(erlang已经可以算的上一个简易微型的OS了),但是许多的时候,似乎只使用这一部分功能也就足够了.zeromq的代码量,截至到我目前阅读的2.0.10-stable版本,也只有不到2W行代码.提供出去的API也极为简单,但是内部的实现比较”绕”,zeromq是我阅读过的项目中少数的非常需要依赖调试工具跟进代码才能看懂代码流程的项目,同时代码中类的继承层次也比较多,阅读起来并不像它提供的API那样简单直白.后续会对其中的一些难点做一些分析.

需求描述:

API服务器,采用异步IO实现并发,故每个API的执行需要非阻塞,否则会造成整个服务会不可用。有若干API是CPU-intensive的,需要较长执行时间,故希望将其执行任务从服务主服务进程detach。

架构设计:

考虑采用ZeroMQ来detach任务执行和API服务主进程。

使用ZeroMQ的PUSH/PULL模型。API主进程为producer(PUSH),worker进程为consumer(PULL)。

有趣的地方是,producer和consumer可以前者bind后者connect,也可以前者connect后者bind。在这个应用场景中,producer要使用connect,而consumer要bind。而不是相反。否则,一旦worker进程没有启动,那么API主进程的send就会阻塞。

坑:

1、producer bind而consumer connect,导致当worker进程未启动时,API主进程在send时会阻塞,从而阻塞所有服务。

2、worker使用了fork来服务多个PUSH/PULL通道。ZeroMQ socket的创建和连接需要在子进程中进行,而不能在父进程中完成然后在子进程中复制句柄。这一想象中或许可以工作的做法其实并不可行。


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/408687.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-22
下一篇2023-05-22

发表评论

登录后才能评论

评论列表(0条)

    保存