Thrift问题集合,打算用Thrift作为生产工具的先看看这个

1.因为本文会不断更新,所以建议大家去博客看最新版。本文出自cnBlogs的xxxteam,那些无节操的转载,请注明。

 

2.Thrift的定位

    Thrift仅仅是一个方便的、高性能的通信中间件,它并不是真正意义上的web Server 或 web service server,因为它没有面对复杂网络环境的功能与能力,所以,它只能在系统内部的高速的、优良的网络环境下使用。

    用大白话说,那就是,不要把Thrift当IIS或apache来放在公网直接给用户提供服务,因为它面对7 * 24的不间断服务来书,并不稳定。在0.9.0版本,我这边的thrift服务,用户1w多一点点,平均好几秒才1次请求,thrift C# server 已经是平均1个小时崩溃一次。还有几位朋友的情况,崩溃的更厉害。

 

3.Thrift是RPC,不是具有双向通信能力的socket-tcp长连接。

    这一点是针对新手来说的。socket-tcp长连接,在连接建立后,双方都可以向另一方发信息,并且连接可以保持很久。但Thrift不同,虽然Thrift也基于tcp,不过在应用层,它仅仅是一个rpc,遵守rpc模型。rpc模型的运作方式与http很像:客户端向服务端发起连接并请求数据 -> 服务端返回数据 -> 连接断开。因此,rpc模型仅仅只适合 一次性的、单向的通信。需要多次的(持久的)、双向通信的朋友,还是老老实实的用socket-tcp把。

    但是,这里提出一个问题。首先,tcp并不是真正的长连接。因为,要保持连接,需要从一端向另一端,不断地发送询问数据包。tcp协议自动做了这件事,不过它的时间太长了,几个小时才发送一次。也就是说,如果使用tcp连接上去后,对方在几分钟内就异常掉线,并且这段时间内没有显式的数据传输,那么tcp有可能在最坏情况下,几个小时后才发现对方掉线。因此,真正的长连接,是需要自己手工去发心跳包的。多久发一次?半秒?一秒?10秒?这些需要由自己控制。到这一步,问题就简单明了了:使用轮询机制,不断询问服务器有无数据。有就取下来。这个流程实际上是模拟了心跳包的机制,并且这个流程是高可控的,因此推荐这个做法。并且,使用tcp长连接的,基本上是想用这种方式来逃避nat造成的单向连接问题。所以这种方案就更合适了。

 

4.Thrift非常不稳定

    截止到目前,Thrift的版本才是0.9.1,而且开发进度缓慢,几乎一年才更新0.1个版本。由于thrift这个项目非常大,涉及语言非常多,因此它本身的复杂度就非常高,已经远远超出apace的其他项目。其次,因为thrift是开源的,开源具有无责任性,以及不负责任性,同时,apache这个机构本身的人手不足,水平不够,导致Thrift内部漏洞百出,各种不稳定现象。虽然Thrift非常方便,但鉴于它的不稳定,本人给两个建议:

    4.1 仅仅把Thrift用于允许丢失数据,允许较长宕机时间(至少10秒钟以上)的非核心业务。

    4.2 使用了Thrift的朋友,一定要在运行Thrift的服务器上,为它做一个看门狗服务。看门狗是一种产品类型,它的作用是监控主体程序,如果主体程序发生故障,则看门狗会杀死该程序,然后重启这个程序。流程也很简单:

        4.2.1 循环开始位置:

        4.2.2 开门狗访问ThriftServer的某个服务

        4.2.3 如果访问成功,则休息 N 秒,然后回到循环开始位置,继续执行循环。这个N与业务性能、允许宕机时间有关。建议设置为5~10秒。不要太长,也不要太短。

                如果访问不成功,

                     如果不成功次数 <= M 次,则不成功次数++,然后休息 K 秒,最后回到循环开始位置,继续执行循环。M和K值,与业务性能、允许宕机时间有关。建议设置M为3次,K为1秒。

                     否则,杀死ThriftServer进程,1秒后重启它,然后把 不成功次数设置为1, 回到循环开始位置 继续执行循环。

 

5.Thrift的默认js封装,用的是 同步 的远程调用方法。如果该方法的访问时间较长,则网页界面会一直卡住,直到js超时,或成功返回结果。

    只有使用ajax,才能做到异步访问,可惜thrift没用ajax。不过,thrift有异步关键词,大家可以去试试。

 

6.Thrift在0.9.0的AS3有Bug。在使用比较复杂的数据结构时发现,如果第一个字段为i32,则该字段可能因为AS3里的read方法的静态定义错误,导致无法获取第一个i32字段的值。通过把第一个字段作为废弃字段,可以解决这个问题,但这种解决方案显然是不科学的、蛋疼的、无节操的。

 

7.Thrift的C#的http client,是没有自动回收功能(gc)的。因此,在使用了一定的次数后,比如100次,要手动把transport给close(),然后dispose(),最后,把所有变量重新new一遍。如果不这样做,可以发现,每次client访问后,内存会增加一点,并且这些内存一直不会被释放,直到因内存不够(64bit app)或溢出(32bit app),造成程序崩溃。

 

8.Thrift的C# HTTP Server在被client js访问时,非常慢。经过测试,发现是因为Server收到client的请求,对client进行回应是,数据传输是按最基本通信单位,一个单位一个单位地传输,也就是说再大的数据量,它也是几个kb几个kb地传,这种传输方法不慢才怪。【TTransport.cs】:

1 public virtual void Write(byte[] buf)
2 {
3     Write (buf, 0, buf.Length);
4 }

 

或者是它的子过程【TStreamTransport.cs】:

1 public override void Write(byte[] buf, int off, int len)
2 {
3     if (outputStream == null)
4     {
5         throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot write to null outputstream");
6     }
7     
8     outputStream.Write(buf, off, len);
9 }

 

这里没有缓冲,导致数据边制造边Write,性能低。

 

9.有其他问题,欢迎加入QQ群23152359。里面有很多研究thrift的大牛。

posted on 2013-04-25 16:12  xxxteam  阅读(9324)  评论(2编辑  收藏  举报

导航