thrift
- 不支持多态 / 重载.
- 没有异构容器: 容器中元素的类型必须一样.
- 参数 & 返回值不能为 null(强烈建议不要将 null 赋予业务意义).
- 容器中元素不能为 null, 在插入容器前需要做检查, 另外建议将 struct 中 string 元素的默认值设置为 “”
- thrift 0.8 接口返回值为基本类型时,无法返回自定义异常。
http是应用层协议,tcp是传输层协议,http一个请求需要tcp3次握手连接,4次握手断开。请求应答以后http就关闭了,
但是tcp也会关闭。
但是到了http1.1以后,tcp不关闭,默认在请求参数加上 keepalived。
服务器端也要支持长连接的服务器,比如ngnix tomact等。并且有一个timeout,ngnix设置,然后返回客户端
所谓了http长连接其实应该说是tcp的长连接。
要有心跳(关闭长连接),限流(一台服务器不能有很多tcp连接)
thrift
protocol协议层 :定义数据传输格式(2进制还是json等)
- TBinaryProtocol:二进制格式;
- TCompactProtocol:压缩格式;
- TJSONProtocol:JSON格式;
- TSimpleJSONProtocol:提供JSON只写协议, 生成的文件很容易通过脚本语言解析;
- TDebugProtocol:使用易懂的可读的文本格式,以便于debug
transport传输层:定义数据传输方式
- TFramedTransport:以frame为单位进行传输,非阻塞式服务中使用;
- TSocket-使用阻塞式I/O进行传输
- TFileTransport:以文件形式进行传输;
- TMemoryTransport:将内存用于I/O,java实现时内部实际使用了简单的ByteArrayOutputStream;
- TZlibTransport:使用zlib进行压缩, 与其他传输方式联合使用,当前无java实现;
Thrift支持的服务模型 - TSimpleServer:简单的单线程服务模型,常用于测试;
- TThreadPoolServer:多线程服务模型,使用标准的阻塞式IO;
- TNonblockingServer:多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式);
Transport: 传输层,定义数据传输方式,可以为TCP/IP传输,内存共享或者文件共享等
protocol: 协议层, 定义数据传输格式,可以为二进制或者XML等
Processor: 处理层, 这部分由定义的idl来生成, 封装了协议输入输出流, 并委托给用户实现的handler进行处理.
Server: 服务层, 整合上述组件, 提供网络服务模型(单线程/多线程/事件驱动), 最终形成真正的服务.
// *) 传输层(Transport), 设置监听端口为9000
TServerSocket serverTransport = new TServerSocket(port);
// *) 协议层
TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory(true, true);
// *) 处理层(Processor)
HelloServiceImpl handler = new HelloServiceImpl();
HelloService.Processor<HelloServiceImpl> processor = new HelloService.Processor<HelloServiceImpl>(handler);
// *) 服务层(Server)
TServer server = new TThreadPoolServer(
new TThreadPoolServer.Args(serverTransport)
.protocolFactory(protocolFactory)
.processor(processor));
Thrift跨语言的rpc,安装的目的是为了把IDL接口数据使用编译器生成不同语言的代码,如果使用IDE(已经有插件了)
./thrift --gen java tutorial.thrift 生成java
./thrift --gen cpp tutorial.thrift 生成c++
客户端
/ 设置调用的服务地址为本地,端口为8080,超时设置为30秒
transport = new TSocket(“localhost”, 8080, 30000);
// 协议要和服务端一致
TProtocol protocol = new TBinaryProtocol(transport);
HelloWorld.Client client = new HelloWorld.Client(protocol);
transport.open();
// 调用接口方法
String result = client.sendString(“Hello World!”);
服务器端
// 关联处理器
TProcessor tProcessor = new HelloWorld.Processor<HelloWorld.Iface>(new HelloWorldServiceImpl());
// 设置服务端口为 8080
TServerSocket serverSocket = new TServerSocket(8080);
// 简单的单线程服务模型
TServer.Args tArgs = new TServer.Args(serverSocket);
tArgs.processor(tProcessor);
// 设置协议工厂为 TBinaryProtocol.Factory
tArgs.protocolFactory(new TBinaryProtocol.Factory());
TServer server = new TSimpleServer(tArgs);
// 启动服务
server.serve();
阿里分布式架构SOFA
1、首先客户端发起请求调用Stub
2、生成Stub,拦截调用的信息
3、通过路由寻址操作找到从路由表中和注册中心中找到对应的调用的服务的地址
4、通过Java序列化的方式将数据转换为二进制进行传递
5、服务器接收到请求之后进行解码操作
6、解码完成之后对于对象进行反序列化的操作
7、通过反射调用对应的发布的服务Bean
8、进行进一步的业务处理逻辑
Stub和skeleton可以理解成是两个代理,Stub是客户端的 封装了远程调用的细节(序列化,即去找远程的主机,服务ip,端口等 发送socket请求),为了客户端调用像调用本地环境一样。
Skeleton是服务端的,作用也一样,封装细节(反序列化 反射调用等,找到对应的bean和方法)