thrift使用指南

2016-08-06
使用指南
多个系统间存在相互调用,同步调用可用的方式有tcp层的dubbo、thrift,http层的rest、grpc,使用zookeeper进行服务的注册与发布管理。异步调用可使用消息队列。通过tcp层通信的dubbo、thrift比普通的rest通信耗时快2-3个数量级,所以系统间调用尽量使用dubbo或thrift通信。

安装thrift

在apache官网下载的thrift为源码,需编译才可用,mac环境下编译thrift还需要添加boost和libevent依赖(中间会因为缺少openssl而编译失败)。安装较复杂,可使用brew安装的方式。

编写thrift接口

  • 下面编写一个HelloWorld.thrift 来测试一下,内容如下:

    namespace java net.mamian.thriftTest.service
    
    service HelloWorldService {
         string sayHello(1:string username)
    }
    
  • 生成java接口
    • thrift -gen java HelloWorld.thrift
    • 将在同级目录下生成gen-java/net/mamian/thriftTest/service/HelloWorldService.java文件。

编写服务端

pom添加如下maven依赖
<dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.9.2</version>
    <type>jar</type>
</dependency>
<dependency>
    <groupId>com.101tec</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.4</version>
    <type>jar</type>
</dependency>
将thrift生成的service文件复制到自己的服务端项目中net.mamian.thriftTest.service目录下
编写service接口的实现类HelloWorldServiceImpl如下:
public class HelloWorldServiceImpl implements HelloWorldService.Iface {
    @Override
    public String sayHello(String username) throws TException {
        return "马面测试thrift调用是否成功。若您看到了此条信息,说明thrift调用成功。";
    }
}
添加thrift、zookeeper配置类
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.PostConstruct;
import net.luoteng.muser.service.HelloWorldService;
import net.luoteng.muser.service.impl.HelloWorldServiceImpl;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TTransportException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ThriftConfig {

    ExecutorService executor = Executors.newSingleThreadExecutor();

    @Bean
    public TServerTransport tServerTransport() {
        try {
            return new TServerSocket(7911);
        } catch (TTransportException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Bean
    public TServer tServer() {
        //发布服务
        HelloWorldService.Processor processor = new HelloWorldService.Processor(
                new HelloWorldServiceImpl());
        TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(
                tServerTransport()).processor(processor));
        return server;
    }

    @PostConstruct
    public void init() {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                tServer().serve();
            }
        });
    }

}


import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.PostConstruct;
import org.I0Itec.zkclient.ZkClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ZooKeeperConfig {

    @Value("${service.name}")
    String serviceName;

    @Value("${zookeeper.server.list}")
    String serverList;

    ExecutorService executor = Executors.newSingleThreadExecutor();

    @PostConstruct
    public void init() {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                registService();
                try {
                    Thread.sleep(1000 * 60 * 60 * 24 * 360 * 10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    //注册服务
    public ZkClient registService() {
        String servicePath = "/" + serviceName;//根节点路径
        ZkClient zkClient = new ZkClient(serverList);
        boolean rootExists = zkClient.exists(servicePath);
        if (!rootExists) {
            zkClient.createPersistent(servicePath);
        }
        InetAddress addr = null;
        try {
            addr = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        String ip = addr.getHostAddress().toString();
        String serviceInstance = System.nanoTime() + "-" + ip;
        // 注册当前服务
        zkClient.createEphemeral(servicePath + "/" + serviceInstance);
        System.out.println("提供的服务为:" + servicePath + "/" + serviceInstance);
        return zkClient;
    }

}
在application.properties中增加thrift、zookeeper配置信息如下
#service name
service.name=cloud-thrift-service
zookeeper.server.list=127.0.0.1\:2181

编写客户端

pom添加如下maven依赖(与服务端一样)
<dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.9.2</version>
    <type>jar</type>
</dependency>
<dependency>
    <groupId>com.101tec</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.4</version>
    <type>jar</type>
</dependency>
将thrift生成的service文件复制到自己的服务端项目中net.mamian.thriftTest.service目录下
编写ServiceProvider(相当于本地service)
import java.util.Map;
import java.util.Random;
import org.springframework.stereotype.Component;
import net.luoteng.mpayment.config.ZooKeeperConfig;
import net.luoteng.mpayment.service.HelloWorldService;

@Component
public class HelloWorldServiceProvider {

    public HelloWorldService.Client getBalanceUserService() {
        Map<String, HelloWorldService.Client> serviceMap = ZooKeeperConfig.serviceMap;
        //以负载均衡的方式获取服务实例        
        for (Map.Entry<String, HelloWorldService.Client> entry : serviceMap.entrySet()) {
            System.out.println("可供选择服务:" + entry.getKey());
        }
        int rand = new Random().nextInt(serviceMap.size());
        String[] mkeys = serviceMap.keySet().toArray(new String[serviceMap.size()]);
        return serviceMap.get(mkeys[rand]);
    }

}
controller层直接使用ServiceProvider
  • 向controller注入ServiceProvider

    @Autowired
    private HelloWorldServiceProvider helloWorldServiceProvider;
    
  • api中使用ServiceProvider

    HelloWorldService.Client svr=helloWorldServiceProvider.getBalanceUserService();
    String result= svr.sayHello("aldsfjpqoij43efonawoie4r");
    
在application.properties中增加thrift、zookeeper配置信息如下
#service name
service.name=cloud-thrift-service
zookeeper.server.list=127.0.0.1\:2181

测试rpc通信

  • 启动zookeeper
    • 下载zookeeper并修改conf/zoo_sample.cfg为zoo.cfg(可个性化自己的配置)
    • sudo bin/zkServer.sh start
  • 启动服务端
    • mvn spring-boot:run
  • 启动客户端
    • mvn spring-boot:run
  • 调用rest
    • 127.0.0.1:10020/api/v1/test

Kommentare: