多个系统间存在相互调用,同步调用可用的方式有tcp层的dubbo、thrift,http层的rest、grpc,使用zookeeper进行服务的注册与发布管理。异步调用可使用消息队列。通过tcp层通信的dubbo、thrift比普通的rest通信耗时快2-3个数量级,所以系统间调用尽量使用dubbo或thrift通信。
安装thrift
在apache官网下载的thrift为源码,需编译才可用,mac环境下编译thrift还需要添加boost和libevent依赖(中间会因为缺少openssl而编译失败)。安装较复杂,可使用brew安装的方式。
安装命令如下
- /usr/bin/ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”
- brew install thrift
编写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