Thrift & Netty

1 thrift协议

  优点:thrift协议性能高,官方类库可扩展性好,提供了多种语言的类库,

    基于.thrift这种类似头文件的中间格式方便文档共享。
 缺点:官方文档不够详尽,使用过程中(java版 libthrift.jar)遇到一些坑: 
      1) 基本类型写入时要调用set方法,如果用字段赋值的方式则写不进去

       (默认情况下会给POJO生成public的字段,初学者很容易被坑)

       (研究源码发现,thrift给基本类型分配一个bitmap标记,第几个数值被赋值则在相应位置置1,

         写入时以此为依据判断字段有没有设置)
      2) 对null对象支持不好,集合类型(或Map的Value)不能add null元素,否则读的时候发生异常。

 

2 实现

  libthrift 不但提供了序列化类库,也提供了一个完整的RPC功能,包括各种可选的Server实现和TProtocol实现
Facebook 官方也提供了一个基于netty3版本的服务端实现:nifty

3 问题

    一切看起来还算好,实际工作中还是遇到了一些问题。公司的项目使用thrift已经三年多了,随着访问量的增加渐渐出现了性能问题。
也增加了几十台机器,但很快就到了瓶颈,异常增多,看机器和线程池状态,大量的请求进不去,线程池很忙,使用的是 TThreadPoolServer
好像官方推荐的就是这个,起初增大了线程数缓解了问题,但后来线程数已经配置的很大,不能再增加了,性能问题越来越严重。

4 解决

后来接触了netty, 看了两本书:《Netty In Action》和李林峰的《Netty权威指南》,就开始考虑基于netty开发一套NIO的Thrift Server。

开发了几天发现粘包是个问题,因为之前的同事发出去的客户端包通信都是基于IO流的,很难知道什么时候客户端发送完成。而Netty官方推荐的各种最佳实践都是基于frame的,即不管怎样总要搞个标记让反序列化的一段容易知道请求内容在哪结束,常见的做法就是在请求的开头四个字节存放整个请求的大小,发现libthrift的异步客户端也是这么做的,那怎么办?让客户端升级?可没那么容易,另外部署一套NIO Server?麻烦,如何平滑升级也是个问题。


百度一下发现了nifty,挺好的,官方已经有解决方案了,省的自己造轮子了。Nifty同时兼容IO流和异步Frame两种通信方式。

一开始没明白什么原理,细看也很简单,那就是先看开头如果是大于0x80认为是有效的IO流协议,每次来一帧都尝试解析,如果没有异常那就是完整的请求了。

否则(开头很可能是0,因为message不需要那么大长度,三个字节已经大约16M了),尝试认为是Frame协议,前四个字节解析成一个int,得到总长度就好办了,不用每次请求都傻傻的试一试看行不行。


花了半天时间上线了nifty版本的Server,请求数瞬间翻倍,不出所料,大量的请求被挡在门外了。

传统的一客户一线程的模式把网络读写和业务逻辑运行在同一个线程,限制了整体处理能力,Netty果然很牛逼。

    主要问题解决了,不过还有些小问题。thrift协议的调试不太方便,Http协议多方便,浏览器输入一个地址就能看的结果,大量的J2EE服务使用HTTP+JSON。

于是我想,要是服务器同时也支持HTTP+JSON协议就好了,看看Nifty, ThriftTransportType枚举类就有HTTP,不过它在Encoder里面很愉快地抛出了NotSupportHttp的异常网上搜索发现libthrift也支持http,0.9.3版本还专门搞了个TServlet与J2EE服务对接,额,我们用的是0.9.1版本,怪不得没发现呢。支持是支持了但可悲的不能同时支持TCP 和 HTTP。

而且还有个严重的问题,thrift的JOSN协议有俩: TJSONProtocol 和 TSimleJSONProtocol ,前者使用不便,序列化太麻烦,TSimleJSONProtocol呢,它很奇怪的标明了是只写协议,啥?不能读?也就是不能通信了呗,表示无语。

又花了两天时间改造TSimleJSONProtocol,改成了可以读写,测通了,ok。接下来,改造nifty,后来也上线了。


这段时间,又考虑造轮子的事(念念不忘轮子),netty4已经稳定很久了,netty5也有尝鲜版,于是基于netty5搞了个nettythrift项目。

不同于nifty的是:

1)同时支持HTTP 

2)支持简单JSON协议(TSimleJSONProtocol)

3)动态协议选择,不用再传 TProtocolFactory

4)业务用单独的线程池,读:IO线程,写:又POST到IO线程

5)对void方法可配置为直接响应给客户端,即:请求解析完服务器直接写回响应,这些都在IO线程,

   之后再把任务提交到业务线程,减少了一次线程切换。

项目开源到Githubhttps://github.com/houkx/nettythrift/     欢迎读者提出意见建议

io.nettythrift包含服务端和客户端demo和测试Case,

 另外还包括三个mini客户端(体积小无依赖,适合android端), 客户端还有一个简单连接池实现。

 
 
 
 


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值