微信号:kant_prog

介绍:关注Java和Python和云计算技术分享,主要分享一些进阶类的内容希望更多“成长中的程序员”可以从这些内容中学会“思考”.

RabbitMQ+Raspberry Pi实现网络监控

2016-07-26 22:29 fireflyc

一个例子

为了方便我们讨论,这里提供一个看起来很高上大的例子。

举个例子,我们公司在魔都有很多办公场地,我希望知道每个地方今天的网速如何。所以我在每个场地都放了一个树莓派,里面装了一个Python,通过它连接到公网上的RabbitMQ;同时我还有一个测试用例服务器每天早上6点它会给每个场地推送“测试用例”,干完活之后它会把测试情况(上传速度、下载速度)发送给服务器端。

连接起来,连接起来,连接起来

这个例子的通讯包括两个需求:

  • 服务器推送测试用例给树莓派

  • 树莓派返回服务器测试测试结果


服务器->树莓派

看起来很简单,只需要给每个树莓派定义一个testcase队列,通过一个direct类型的exchange绑定起来就行了


比如:闵行(test_case.mh)、浦东(test_case.pd)。服务器推送测试用例的时候就是对network_speed_test发送相应的key和data就行了。比如推送给闵行的,只要

channel.basicPublish("netwokr_speed_test", 
                   "test_case.mh", null, testCase.getBytes());

其中testCase是测试用例的序列化后的字节流。

树莓派->服务器

这个也看起来非常简单,定义一个server.test_report队列。然后和network_speed_server绑定起来。(为了区分,这里不使用network_speed_test这个exchange)


树莓派上会送测试报告也很简单:

channel.basicPublish("network_speed_server", 
                "server.test_report", null, testReport.getBytes());

实时,实时,实时

RabbitMQ帮我解决了大问题,这一种天气不用再满大街的跑检查网速了。空调,沙发,wifi,葛优躺


但是上面的小程序只能解决提前检查网速的问题,如果有人说自己上不去网了,那我的惨了。顶着烈日去现场。。。。。。想想都觉得可怕。既然有树莓派——在现场了,我其实就不用到现场了。所以我希望增加一个实时功能,可以看到当前是树莓派是不是在线(不在线证明真的上不了网络);如果在线,我实时的发送一条ping命令检查一下它的网络请求是否正常。第一条很容易满足,RabbitMQ维护的是一个长连接,通过Web API可以实时看到当前有哪些客户端是连接在上面的。第二条看起来不是MQ的专长,这是一个同步通讯。所以直觉告诉我们要开一个HTTP Server,然后暴露出接口,但是,树莓派上面根本没有公网IP,即便开放接口我也不可能访问到,似乎只剩下一条路可选了——让树莓派轮询服务器端,实时执行。想想这些头皮就发麻,万幸RabbitMQ提供了同步通讯的办法,原理很简单,一幅图表示:


  • 测试服务器定义一个临时队列,启动一个消费者等待临时队列(有超时时间)

  • 测试服务器发送“指令”到test_case队列,指定AMQP头部reply_to数据为临时队列的名字(消息可以有超时时间ttl)

  • 树莓派执行指令,检查reply_to,发送数据到reply_to

  • 测试服务器消费者收到执行结果,返回

其中值得注意的是,不考虑超时如果树莓派挂掉了,测试服务器会有一个消费者一直在傻傻的等待。所以这里必须考虑超时(消费者超时),消息本身也要考虑超时,否则树莓派重启之后会突然得到大量的消息执行之后也没有任何意义(服务器端消费者已经超时终止,reply_to队列已经被销毁)有人会质疑这种是“伪同步”通讯,其实我们仔细想一下所有的同步通讯都会有超时。我们发起一个HTTP请求难道是真的“同步”?唯一的区别是RabbitMQ的这种同步通讯是通过中间人实现的而不是直接相互通讯的,仅此而已。这个特性在AMQP叫RPC,在RabbitMQ中对它进行了特别的优化——fast rpc,这种机制下可以省去绑定队列的开销。一次调用的开销主要集中在实时生成一个queue,这个上限仅仅取决于系统的内存。(RabbitMQ用Erlang编写,一个Queue代表一个process,Erlang可以拥有的process数量取决于你的内存)

总结

消息通讯中间件是一种应用通讯机制,通过这种机制可以把不同的应用,不同的系统连接起来。传统的认为消息通讯中间件只能做异步通讯,对于RabbitMQ来说它同时支持异步和同步通讯。
文章中没有提供代码示例(如果需要,我稍后放出),因为我觉得RabbitMQ的参考资料太多了。一抓一大把,特别是官方的6个小例子简直是——简单、明了。RabbitMQ适合作为消息总线的原因主要有三:

  1. 支持的客户端库多,基本上你能想到的都支持,而且是官方支持,而且持续增长(本来以为没有OC库,去年写了一个 https://github.com/fireflyc/LibRabbitMQ-OC 前几周突然发现官方居然自己偷偷的写了一个“官方版” )

  2. AMQP的模型非常灵活

  3. 同时支持异步和同步

我对消息总线的理解是——集成,总线应该定义通讯模型而不应该定义通讯数据。从这个意义上讲,WebService或者SOA不符合这个要求,它是强制SAOP协议或者XML协议的(好吧,至少广义上如此),而作为负责集成的消息总线应该允许不同类型的数据传送,也不必关心数据的内容,总线上通讯双方自己决定如何解包、封包数据换句话说,我们需要的是——负责通讯中间件,这个中间件仅仅通讯除此之外不要在干别的事情。(这也是zeromq的设计初衷)

欢迎关注公众账号了解更多信息“写程序的康德——思考、批判、理性”


 
写程序的康德 更多文章 程序员学哲学 谈谈编程范式 工程化你的Python项目 工程化你的Python项目 如何测试存储(上)
猜您喜欢 Power8极限算法挑战赛圆满落幕 放肆的使用UIBezierPath和CAShapeLayer画各种图形 教师节,老师竟然送你礼物!(9.10日,不限名额!!!) 除了JS代码,还有哪些方法能让用户秒到限量月饼 微服务架构下分布式Session管理