Skip to content

Instantly share code, notes, and snippets.

@ninehills
Created June 18, 2013 12:17
Show Gist options
  • Star 41 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save ninehills/5804894 to your computer and use it in GitHub Desktop.
Save ninehills/5804894 to your computer and use it in GitHub Desktop.
ZeroRPC简介 - 轻量级分布式通信框架

ZeroRPC简介 - 轻量级分布式通信框架

概述

分布式系统的核心是分布式通信,而传统上开发一套支持上千台规模集群,可靠性非常高的分布式通信框架,需要不少的精力投入。而在多数情景下,我们(特别是时间宝贵的OP)并不是非常关注技术实现的细节,而是希望有一套成熟、轻量、可靠性高、使用方便而且易于调试的分布式通信框架,可以直接使用,从而把时间放在具体业务逻辑上。

在PyCon 2012大会上,dotcloud公司开源了一套基于ZeroMQ和MessagePack的分布式通信框架(或者说是协议+Python实现)。该框架因为基于ZeroMQ,使用方法是RPC,所以被命名为ZeroRPC。ZeroRPC的特点在其官网的介绍中一目了然[1]:

ZeroRPC is a light-weight, reliable and language-agnostic library for distributed communication between server-side processes.

ZeroRPC的设计初衷是『simple tool to solve a simple problem』,dotcloud工程师在PPT中提到了他们设计目标[2]:

  1. 最小的使用成本。比如单机时我们这么用import foo; foo.bar(42),分布式后我们希望可以这么用:foo=RemoteService(...) ; foo.bar(42)
  2. 自文档。不需要看远程服务的源代码,我们能够获得远程服务所支持的方法,docstring等等。
  3. 优雅的处理异常。调用远程方法产生的异常,不应该中断远程服务,而应该在本地抛出。(异常比返回状态更方便,更简洁)
  4. 语言无关。同一套协议有多种实现(目前有Python和Node.js两种实现),而且实现简单,目前Python实现只有2000行代码。
  5. 高可用性,快速。目前Python实现基于gevent+zmq,性能非常高。
  6. 良好的debug和profile工具

接下来我们以0.4版的Python实现为例,由浅入深的介绍ZeroRPC框架。

安装

pip install zerorpc

Examples

接下来我们用一批例子来展示ZeroRPC的基本使用方法。

Example: Hello World

Server:

import zerorpc

class HelloRPC(object):
    def hello(self, name):
        return "Hello, %s" % name

s = zerorpc.Server(HelloRPC())
s.bind("tcp://0.0.0.0:8282")
s.run()

Client(Python),和调用本地模块一样的方便:

import zerorpc

c = zerorpc.Client()
c.connect("tcp://127.0.0.1:8282")
print c.hello("RPC")

或者用CLI(debug用):

$ zerorpc tcp://127.0.0.1:8282 hello RPC
connecting to "tcp://127.0.0.1:8282"
'Hello, RPC'

Example: introspection

用cli可以列出远程模块所支持的方法,并可以查看docstring文档:

# 将urllib模块发布
$ zerorpc --server --bind tcp://127.0.0.1:1234 urllib

# 列出远程所有以q开头的方法
$ zerorpc tcp://127.0.0.1:1234 | grep ^q
quote                       quote('abc def') -> 'abc%20def'
quote_plus                  Quote the query fragment of a URL; replacing ' ' with '+'

# 列出quota_plus的文档
$ zerorpc --inspect tcp://127.0.0.1:1234 quote_plus
connecting to "tcp://127.0.0.1:1234"

quote_plus(s, safe=)

Quote the query fragment of a URL; replacing ' ' with '+'

Example: exceptions

ZeroRPC可将远程方法抛出的异常传递到本地,这样不仅符合业务逻辑,而且异常捕获也减少了服务端的容错逻辑,提高了稳定性。

$ zerorpc tcp://127.0.0.1:1234 quote_plus
connecting to "tcp://127.0.0.1:1234"
Traceback (most recent call last):
  ...此处省略
zerorpc.exceptions.RemoteError: Traceback (most recent call last):
  ...此处省略
TypeError: quote_plus() takes at least 1 argument (0 given)

Example: Streaming Responses

Streaming Responses 类似于 Python 的生成器,尤其是在大数据量操作时优势明显。比如有一个很长很大的列表L,如果一次传递过去再进行处理,不仅网络传输需要时间,而且占用内存也较大。此时如果使用Streaming,其实是将列表的每个元素分别传递并分别处理返回(迭代器),效率十分高。

# streaming example, 省略不必要的代码
class StreamingRPC(object):
    @zerorpc.stream
    def streaming_range(self, fr, to, step):
        return xrange(fr, to, step)

# client,省略不必要的代码
for item in c.streaming_range(10, 20, 2):
    print item

Example: high availability

ZeroRPC可以放在Proxy之后,实现高可用性,以HAProxy为例:

启动HAProxy,使其工作在TCP模式,并将请求转发给后端:

$ cat haproxy.cfg
listen zerorpc 0.0.0.0:1111
    mode tcp
    server backend_a localhost:2222 check
    server backend_b localhost:3333 check
$ haproxy -f haproxy.cfg

启动一个或多个后端:

$ zerorpc --server --bind tcp://0.0.0.0:2222 urllib

此时便可用client去连接HAProxy, HAProxy会将请求转发给可用的后端。

$ zerorpc tcp://localhost:1111

实现细节

ZeroMQ和三种通信模型

ZeroMQ[4]是一种基于消息队列的多线程网络库,其对套接字类型、连接处理、帧、甚至路由的底层细节进行抽象,提供跨越多种传输协议的套接字。ZeroMQ是网络通信中新的一层,介于应用层和传输层之间(按照TCP/IP划分),其是一个可伸缩层,可并行运行,分散在分布式系统间。

简单的说,ZMQ提供了完全不同于传统BSD Socket的网络通信接口,屏蔽了Socket的处理细节,并提供了几种通信模型,基本覆盖了分布式系统的需求。

ZMQ提供了以下几种通信模型,而这些通信模型也同样可在ZeroRPC中使用

  • REQ-REP: Request-Reply 模型,类似于传统的通信模型,但ZMQ的Request端和Reply端无论谁先启动均可以,只是请求必须遵循Request-Reply的顺序。
  • PUB-SUB: Publish-Subscribe 模型,Publish节点为信息源,Subscribe节点接收信息。如果Subscribe节点中途退出,不影响信息的继续发布。
  • PUSH/PULL: PipeLine 模型,以扇入扇出的模式连接节点,多用于任务发布和信息收集的场景。

MessagePack

ZeroRPC选择MessagePack[5]作为序列化工具,相比于JSON/BSON/YAML等格式,MsgPack提供20~50倍的序列化速度以及1/2大小的序列化产出。

ZeroRPC协议

完成的协议参见文档[3],简略说,ZeroRPC分为三层:

  1. Wire (or transport) layer 利用ZeroMQ和MessagePack进行通信
  2. Event (or message) layer 最复杂的一层,处理心跳,事件等
  3. RPC layer RPC Request+Response

超时和心跳

由于ZMQ隐藏了Socket细节,所以无法感知断线,于是ZeroRPC采用心跳包的方式进行在线检测。Client端在断线后会抛出LostRemote异常。默认断线超时为30s,可设定。

身份验证和传输加密

目前版本的ZeroRPC没有实现任何形式的身份验证,传输加密官方建议通过SSL实现。

中间件

最新版本的ZeroRPC支持middleware API,比如StatsD Middleware[6],可以跟踪Request/Response的耗时并传送给StatsD,以分析系统性能。

Show me the code

https://github.com/dotcloud/zerorpc-python

由于文档较缺失,如果需要了解的更深,建议直接阅读源代码,2000行不到,短小精悍。

参考文档

  1. http://zerorpc.dotcloud.com/
  2. Talk: ZeroRPC at PYCON2012
  3. ZeroRPC Protocol
  4. http://zguide.zeromq.org/page:all
  5. http://msgpack.org/
  6. https://github.com/aluzzardi/zerorpc-statsd
@easyforgood
Copy link

Good job

@Noaiii
Copy link

Noaiii commented Aug 6, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment