作者归档:notedit
构建自己的rpc protocol
rpc的的框架写过好几个了,协议部分大都是参照redis mysql mongodb 的协议来实现的,其中有一个已经在生产环境中运行了几个月了,到目前为止运行良好。用现有的一些协议来进行通信有一个好处就是,rpc的client部分只是简单的封装一下他们现有client 的实现就可以。不好的地方就是现有的协议有很多内容不是你真正想要的,比如我在用mongodb的协议在实现一个rpc的时候,我只用到了他的query请求,但是我要在server端实现跟query相关的一系列的协议处理。这并不是我想要的。 当然要完全实现自己的一套协议的话,需要做的也很多:要实现自己的client,rpc消息的打包解包啊之类的工作,和使用redis mysql mongodb 的协议相比我更喜欢一个纯粹的比较干净的rpc协议。 先说一下这个rpc的用途吧,前端用nodejs调用后端的接口然后进行视图的渲染,后端用golang提供数据层的封装。综合考虑之后决定使用bson来进行数据的编码和解码。 一个请求分为两部分:消息头 和 消息体。 消息头: 消息头用四个字节表示,采用大端字节序进行表示,这样的话每个数据包最大可以是2的32次方,如果消息体有20个字节的话。消息头应该就是这样的: 00000000 00000000 00000000 00010100 消息体: 消息体主要分为四种:call reply error info,并全部采用bson编码。 call 消息体的格式为: {call:{funcname:’function name’,arguments:’arguments’}} reply 消息体的格式为: {reply:’result’} or {reply:noreply} error 消息体的格式为: {error:{message:’message’,detail:’detail’}} message: 是一个标示符,用来表示错误类型 detail:是错误的描述 注意这里的错误信息有时候会返回给用户 … 继续阅读
根据mongo protocol 写了个rpc 框架
最近研究协议上瘾了,从memcache protocol , redis protocol,再到复杂的mysql protocol,还有最近几天看的mongo protcol .最让我感到欢喜的是mongo protocol. 协议很简洁, 外加用bson来序列化数据,bson支持的数据类型很多可以和python进行互相转化.选用mongo protocol 和bson 主要有如下优点: 数据量很小而且解析很快(具体的可以自行google). 之前有研究过protocol rpc,给人的感觉就是不太灵活,输入和返回都要定义一个对象.用bson 来传的话全是dict 操作,很灵活. mongodb 客户端众多,简单的对客户端进行封装一下就是一个rpc 的client,理论上可以支持很多种语言, 可以很好的mongodb 结合起来 以上四点就足够让我兴奋的了,还有就是前一段时间学了twisted,一直也想用twisted 写点东西,于是这个oocrpc就出来了. 正好最近也在看 (Out of Control), 就给它起个oocrpc 的名字,名字听起来有点霸气~~~~~~ 写代码的时候同时参考了gashero写的 magicrpc 和 txmongo 的代码.
mongodb protocol 分析
Mongo Wire Protocol 前一段时间研究一下mysql protocol 还有 mysql udf,mysql protocol 搞明白了,也用twisted 实现了一下mysql protocol.但结果令我很恼火,mysql protocol 不足够简洁,自己捣鼓的一个项目也做到一半做不下去了.然后就看到了mongodb protocol ,简单的看了一下–清爽,简洁.甚合我意,于是,研究之. Introduction mongo protocol 是一个简单的依据socket 的,请求-回应型的协议.用来进行mongo client 和 mongo server 之间的数据交互. client 可以通过一个正常的 tcp/ip socket 来连接server.默认的client 和server 之间没有handshake(握手). Messages Types and Formats 下面只讲几个我可能用到的几个消息类型 和格式 Standard … 继续阅读
twisted系列教程十九–cancel deferred
Part 19: I Thought I Wanted It But I Changed My Mind 原文:http://krondo.com/blog/?p=2601 作者:dave 译者:notedit 时间:2011.07.03 Introduction twisted 是一个正在发展的项目,twisted 的开发者们会添加一些新的特色或者扩展旧的.随着twisted 10.1.0 的发布,开发者们增加了一个新的功能–取消,这个就是我们今天要讲的内容. 异步的程序把request 和response 进行了解耦,于是增加了一个新的可能:在发送一个请求和得到返回结果之间你可以决定是否你还要返回结果.细想一下第十四部分的poetry proxy server.下面是这个代理怎么工作的(第一次没有缓存的时候): 一个请求进来 这个proxy 连接真正的server去获取诗 一但获取到完整的诗,发送给client 一切工作的很好,但是假如client在得到诗之前挂起了怎么办?这样的话我们的proxy 就会被卡住.在出现这种情况的时候我们最好的办法就是关掉连接. 回想一下图片十五,一个描述了同步程序中概念上的流程控制的图表.在这个图片中我们可以看到函数调用往下走,异常往上走.假如我们想取消一个同步的调用,程序的流程会和函数调用的方向是一样的,从高层代码到底层代码.图片三十八描述了这个过程: 当然,在一个同步的程序中这个是不可能的因为高层的代码不会恢复运行直到底层的代码运行完,在这时就没有什么可以取消的了.但是在一个异步的程序中,高层的代码在底层的代码运行完之前控制着程序,这就让我们有能力取消底层次的请求. 在一个twisted 程序中,底层的请求是被deferred对象所体现的.在deferred 中信息流是向下的,从底层的代码到高层的代码,这个和同步程序中return 信息流是相同的.从twsited 10.1.0 … 继续阅读
twisted系列教程十八–异步操作的并行运行
Part 18: Deferreds En Masse 原文:http://krondo.com/blog/?p=2571 作者:dave 译者:notedit 时间:2011.07.02 Introduction 在上一部分我们学习了一种新的用生成器来组织一系列异步callbacks 的方法.加上deferred,我们已经有两种组织异步操作的方法了. 有时候,我们想让一组异步操作并行的运行.因为twisted 是单线程的,它不会真正的并行的运行,但是我们想要异步的I/O 在一组任务上运行的尽可能的快.比如我们的poetry client,从多个server上同时下载诗,而不是一个接一个的.这就是我们为什么用twisted. 我们的opetry client 不得不解决这个问题:你怎么知道你所有的异步操作什么时候能结束?目前为止我们是用把所有的返回结果放进一个list里面,并检查这个list 的长度.我们必须在收集结果的时候非常注意,因为一个错误的结果可能让我们的程序永久的运行下去. 就如你想象的那样,twisted 包含了一个解决这个问题的抽象,我们今天就会学习一下它的用法. The DeferredList DeferredList类允许我们把一个deferred 对象的列表当成一个deferred来对待.这样的话我们就可以开启多个异步的操作并在它们全部执行完的时候得到通知.让我们看一些例子. 在deferred-list/deferred-list-1.py,你会发现这些代码: from twisted.internet import defer def got_results(res): print ‘We got:’, res print ‘Empty List.’ … 继续阅读
twisted系列教程十七–用inlineCallbacks来管理callbacks
Part 17: Just Another Way to Spell “Callback” 原文:http://krondo.com/blog/?p=2441 作者:dave 译者:notedit 时间:2011.06.30 Introduction 在这一部分我们继续回到callback.我们将介绍用生成器来写callbacks.我们会讲到这个技巧怎么工作的,还有它和Deferred 的比较.最后我们会用这个技巧重写我们的poetry client.首先我们要回顾一下生成器是怎样工作的,人后我们就会明白为什么它是创造callbacks 的一个替代品. A Brief Review of Generators 你可能已经知道,python 的生成器是一个可以重新启动的函数,你可以用yield来实现重新启动的功能.通过yield,这个函数就变成了一个生成器函数,它会返回一个迭带器,并可以将一个函数分成一系列的步骤来运行.迭带器的每一个循环都会重启这个函数,这个函数会继续运行直到遇到下一个yield. 生成器(和迭带器)经常用来表示生成一系列的返回值.先看一下我们的例子inline-callbacks/gen-1.py: def my_generator(): print ‘starting up’ yield 1 print “workin’” yield 2 print “still workin’” yield … 继续阅读
twisted系列教程十六–twisted守护进程
Part 16: Twisted Daemonologie 原文:http://krondo.com/blog/?p=2345 作者:dave 译者:notedit 时间:2011.06.28 Introduction 到目前为止我们写的server 还运行在一个终端里面,通过print 语句向外输出内容.开发的时候这样做是很有好处的,但是当你部署一个产品的时候这样就不好了.一个生产环境中的server应该是: 作为一个守护进程运行,不和任何的终端和会话相连.你不会希望当你登出的时候,你的server 也会退出 把debug和错误信息输出到一个日志文件中,或者syslog 服务中 低权限的,比如,用一个低权限的用户运行 把它的pid 记到一个文件中,管理员可以很容易的向守护进程发送信号 twisted 已经提供了对上面四条的支持.但首先我们首先要先改变一下我们的代码. The Concepts 要想理解twisted 你需要学习一些新的概念.最重要的一个概念是Service,一般来说,一个新的概念往往和一个或多个接口对应. IService IService接口定义了一个可以被停止和开启的service.这个service 做什么呢? 你可以做任何你想做的,这个接口仅仅需要一些很少的参数和方法(它定义的少,你可以实现的就多),而不是定义了特定的函数的一种service. 这个接口需要两个属性:name 和 running.name属性只是一个字符串, 例如”fastpoetry”或者None,running 属性是一个布尔类型,假如这个service被成功的开启,这个值为true. 我们只会接触ISservice 的一些方法.我们会略过那些高级的不常用的方法.IService 的两个基本方法是startService 和stopService: def startService(): … 继续阅读
twisted系列教程十五–测试twisted代码
Part 15: Tested Poetry 原文:http://krondo.com/blog/?p=2273 作者:dave 译者:notedit 时间:2011.06.27 Introduction 在这个系列中我们也已经写了很多twisted 代码了,但目前为止我们忽略了一个很重要的事情—测试.你可能也一直在想我们怎样用一个同步的测试框架unitest来测试我们的异步的程序.简短的回答是不能,我们已经发现,同步的程序和异步的程序不能混合在一起.最起码不会很好的结合在一起. 幸运的是,twisted 已经包含了他自己的异步测试测试框架–trial.我们也可以用它来测试同步的框架. 我们假设你已经对unittest 的测试原理和测试框架比较熟悉了,在unittest 中,我们通过定义一个继承TestCase的类创建测试,并且每个测试方法前面以test为前缀.框架会帮你发现测试,运行测试,然后报告出测试结果. The Example 你会在tests/test_poetry.py发现一些例子代码.为了保证我们的例子可以自包含,我们已经把全部的有必要的代码拷进test 模块.正常的来说,你只需要导入你想测试的模块就可以了. 这个例子测试了client 和server,通过使用这个client 去从test server 上获取到每一首诗.为了提供一个可供测试的server,我们在我们的测试用例中实现了setUp 方法: class PoetryTestCase(TestCase): def setUp(self): factory = PoetryServerFactory(TEST_POEM) from twisted.internet import reactor self.port = reactor.listenTCP(0, … 继续阅读
twisted系列教程十四— pre-fireed deferred
Part 14: When a Deferred Isn’t 原文:http://krondo.com/blog/?p=2205 作者:dave 译者:notedit 时间:2011.06.27 Introduction 在这一部分我们将要学习deferred 类的另外的一个方面.为了促进讨论,我们要为我们的poetry service增加一个server.假设我们有大量的内部的client 想要连接一个相同的外部的server.假设这个server已经很慢而且已经负载很高了.我们不想再让server上连接更多的client 了. 所以我们会创建一个缓存代理服务器.当一个client 连接到proxy的时候,这个proxy或者从外部的server获取到一首诗或者就返回一个之前已经缓存了的内容.我们可以让我们的client 都连接proxy,我们的外部的server 的负载就会很小.我们可以用图片三十来描述这个过程: 思考一下当一个client连接到proxy 之后会发生什么,假如这个proxy 的缓存是不存在的,这个proxy必须异步等待外部的server 返回一个结果然后才能返回client.到目前为止还不错,我们已经知道怎样去处理返回deferred 的异步的函数.另一方面,假如在缓存中已经有了一个一首诗,这个proxy 会把它立即返回,一点也不用等待.所以proxy获取一首诗的内容可以是同步的或者是异步的. 所以 我们能做些什么假如我们有一个有时异步有时同步的函数?twisted 提供了很多选项,并且它们依据deferred 的一个我们没有讲的特色:你可以在你返回deferred之前触发它. 这个是管用的,因为尽管你不能触发一个deferred 两次,但是你可以在deferred 触发之后向deferred 中增加callbacks 和 errbacks.当你这样做的时候,deferred 会继续的触发 callback/errback 链 从上次它离开的地方.一个很重要的一点是一个已经触发的deferred … 继续阅读