Consul + Thrift 搭建分布式微服务

309 阅读4分钟

Consul + Thrift 搭建分布式微服务

最终项目工程结构

.
├── example.thrift
├── gen-java
│   └── com
│       └── kabai
│           └── thrift
│               ├── User.java
│               └── UserService.java
├── thrift.consumer
│   ├── pom.xml
│   └── src
│       └── main
│           ├── java
│           │   └── com
│           │       └── kabai
│           │           ├── ThriftClientApplication.java
│           │           ├── config
│           │           │   └── ThriftClientConfig.java
│           │           ├── controller
│           │           │   └── UserController.java
│           │           └── thrift
│           │               ├── User.java
│           │               └── UserService.java
│           └── resources
│               └── application.yml
└── thrift.provider
    ├── pom.xml
    └── src
        └── main
            ├── java
            │   └── com
            │       └── kabai
            │           ├── ThriftServerApplication.java
            │           ├── config
            │           │   └── ThriftServerConfig.java
            │           └── thrift
            │               ├── User.java
            │               ├── UserService.java
            │               └── UserServiceImpl.java
            └── resources
                └── application.yml

准备工作

  1. 安装 Thrift 编译器

    • 你需要先安装 Thrift 编译器,以便将 Thrift IDL 文件编译为 Java 代码。
    • 下载并安装: Thrift 安装指南
  2. 创建 Thrift IDL 文件

    • 定义服务接口和数据结构,例如创建一个文件 example.thrift

      namespace java com.kabai.thrift
      
      struct User {
          1: i32 id,
          2: string name
      }
      
      service UserService {
          User getUserById(1: i32 id)
      }
      

编译 Thrift IDL 文件

  1. 在命令行运行 Thrift 编译器将 IDL 文件编译为 Java 代码:

    thrift --gen java example.thrift
    

    这将生成一个 gen-java 文件夹,包含所有生成的 Java 文件。

版本

我这里本地配置了两个版本,这里演示项目,需要用到jdk17,maven 3.9.7。

  • jdk17
  • maven 3.9.7
  • Spring Boot 3.1.2
  • Packaging jar
# 配置JDK路径
export JAVA_8_HOME=/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home
export JAVA_17_HOME=/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home

# 默认使用 JDK8
export JAVA_HOME=$JAVA_8_HOME
CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:.

# 配置alias命令动态切换JDK版本
alias jdk8='export JAVA_HOME=$JAVA_8_HOME'
alias jdk17='export JAVA_HOME=$JAVA_17_HOME'

export JAVA_HOME
export CLASSPATH

# 配置maven路径
export MAVEN_3_6_1_HOME=/Users/mac/env/apache-maven-3.6.1
export MAVEN_3_9_7_HOME=/Users/mac/env/apache-maven-3.9.7

# 默认使用 3.6.1
export MAVEN_HOME=$MAVEN_3_6_1_HOME
export PATH=$MAVEN_HOME/bin:$PATH

# 配置alias命令动态切换MAVEN版本
alias mvn3.6='export MAVEN_HOME=$MAVEN_3_6_1_HOME && export PATH=$MAVEN_HOME/bin:${PATH//:$MAVEN_3_9_7_HOME\/bin/}'
alias mvn3.9='export MAVEN_HOME=$MAVEN_3_9_7_HOME && export PATH=$MAVEN_HOME/bin:${PATH//:$MAVEN_3_6_1_HOME\/bin/}'

# 导出MAVEN_HOME和PATH变量
export MAVEN_HOME
export PATH

步骤 1: 安装Consul配置中心

确保Consul安装并运行。你可以在本地或者服务器上安装并运行Consul,以下是一些基本步骤:

# 下载并解压Consul
wget https://releases.hashicorp.com/consul/1.10.3/consul_1.10.3_linux_amd64.zip
unzip consul_1.10.3_linux_amd64.zip

# 运行Consul
/root/consul agent -dev -client=0.0.0.0

步骤 2: 创建springboot项目 - 从springboot官网

步骤 3: 创建服务提供者(thrift.provider)

接下来,我们创建一个服务提供者,它将向Consul注册自己的服务,并提供API服务。

  1. 创建一个新的Spring Boot应用程序
package com.kabai;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ThriftServerApplication {
    public static void main(String[] args) {
       SpringApplication.run(ThriftServerApplication.class, args);
    }
}
  1. 添加consul-discovery、libthrift和Spring Web的依赖pom.xml文件中。
  • consul-discovery
  • consul-config
  • libthrift
<dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.14.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
    <version>4.0.3</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    <version>4.0.3</version>
</dependency>
  • 完整pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>3.1.2</version>
       <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.kabai</groupId>
    <artifactId>thrift.provider</artifactId>
    <version>1.0.0-RELEASE</version>
    <name>thrift.provider</name>
    <description>thrift.provider</description>
    <properties>
       <java.version>17</java.version>
    </properties>
    <dependencies>
       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
       </dependency>

       <dependency>
          <groupId>org.apache.thrift</groupId>
          <artifactId>libthrift</artifactId>
          <version>0.14.2</version>
       </dependency>
       <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-consul-config</artifactId>
          <version>4.0.3</version>
       </dependency>
       <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-consul-discovery</artifactId>
          <version>4.0.3</version>
       </dependency>
    </dependencies>

    <dependencyManagement>
       <dependencies>
          <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-dependencies</artifactId>
             <version>2022.0.3</version>
             <type>pom</type>
             <scope>import</scope>
          </dependency>
       </dependencies>
    </dependencyManagement>

    <build>
       <plugins>
          <plugin>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
       </plugins>
    </build>

</project>
  1. 配置thrift-provider连接属性,以连接到Consul服务器。
spring:
  application:
    name: thrift-provider
  cloud:
    consul:
      host: 140.143.xx.xx
      port: 8500
      discovery:
        instance-id: thrift-provider-12345
        service-name: thrift-provider
        register: true
        enabled: true
        heartbeat:
          enabled: true
      config:
          enabled: true
          format: yaml
  config:
    import: "optional:consul:"
  1. 创建一个ThriftServerConfig配置类,配置Thrift。
package com.kabai.config;

import com.kabai.thrift.UserService;
import com.kabai.thrift.UserServiceImpl;
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.protocol.TBinaryProtocol;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ThriftServerConfig {
    @Bean
    public TServer thriftServer(UserServiceImpl userService) throws Exception {
        TServerTransport serverTransport = new TServerSocket(9090); // 使用独立的端口,例如9090
        UserService.Processor<UserServiceImpl> processor = new UserService.Processor<>(userService);

        TThreadPoolServer.Args args = new TThreadPoolServer.Args(serverTransport)
                .processor(processor)
                .protocolFactory(new TBinaryProtocol.Factory(true, true, Integer.MAX_VALUE, Integer.MAX_VALUE));

        TServer server = new TThreadPoolServer(args);
        new Thread(() -> server.serve()).start();
        return server;
    }
}
  1. 拷贝生成thrift文件到thrift.provider工程目录内
cd gen-java #进入生成的Thrift目录
cp -r ./ ../thrift.provider/src/main/java #拷贝进thrift.provider工程目录内
  1. 写你具体的逻辑实现
package com.kabai.thrift;

import org.apache.thrift.TException;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService.Iface {
    @Override
    public User getUserById(int id) throws TException {
        User user = new User();
        user.setId(id);
        user.setName("User" + id);
        return user;
    }
}

步骤 4: 创建服务消费者(thrift.consumer)

最后,我们创建一个服务消费者,它将使用Feign来调用服务提供者的API。

  1. 创建一个新的Spring Boot应用程序
package com.kabai;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ThriftClientApplication {
    public static void main(String[] args) {
       SpringApplication.run(ThriftClientApplication.class, args);
    }
}
  1. 添加OpenFeign、Consul Discovery Client和Spring Web的依赖pom.xml文件中。
<dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.14.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
    <version>4.0.3</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    <version>4.0.3</version>
</dependency>
  • 完整pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>3.1.2</version>
       <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.kabai</groupId>
    <artifactId>thrift.consumer</artifactId>
    <version>1.0.0-RELEASE</version>
    <name>thrift.consumer</name>
    <description>thrift.consumer</description>
    <properties>
       <java.version>17</java.version>
    </properties>
    <dependencies>
       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
       </dependency>

       <dependency>
          <groupId>org.apache.thrift</groupId>
          <artifactId>libthrift</artifactId>
          <version>0.14.2</version>
       </dependency>
       <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-consul-config</artifactId>
          <version>4.0.3</version>
       </dependency>
       <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-consul-discovery</artifactId>
          <version>4.0.3</version>
       </dependency>
    </dependencies>

    <dependencyManagement>
       <dependencies>
          <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-dependencies</artifactId>
             <version>2022.0.3</version>
             <type>pom</type>
             <scope>import</scope>
          </dependency>
       </dependencies>
    </dependencyManagement>

    <build>
       <plugins>
          <plugin>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
       </plugins>
    </build>

</project>
  1. 配置thrift-consumer连接属性,以连接到Consul服务器。
spring:
  application:
    name: thrift-consumer
  cloud:
    consul:
      host: 140.143.xx.xx
      port: 8500
      discovery:
        instance-id: thrift-consumer-67890
        service-name: thrift-consumer
        register: true
        enabled: true
        heartbeat:
          enabled: true
      config:
        enabled: true
        format: yaml
  config:
    import: "optional:consul:"

server:
  port: 8280
  1. 创建一个ThriftClientConfig配置类,配置Thrift。
package com.kabai.config;

import com.kabai.thrift.UserService;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

@Configuration
public class ThriftClientConfig {

    private final DiscoveryClient discoveryClient;

    public ThriftClientConfig(DiscoveryClient discoveryClient) {
        this.discoveryClient = discoveryClient;
    }

    @Bean
    public UserService.Client userServiceClient() throws Exception {
        List<ServiceInstance> instances = discoveryClient.getInstances("thrift-provider");
        if (instances == null || instances.isEmpty()) {
            throw new IllegalStateException("No instances of thrift-provider found");
        }
        ServiceInstance serviceInstance = instances.get(0);
        TTransport transport = new TSocket(serviceInstance.getHost(), 9090); // 确保使用的是服务端配置的独立端口
        transport.open();
        TProtocol protocol = new TBinaryProtocol(transport, Integer.MAX_VALUE, Integer.MAX_VALUE);
        return new UserService.Client(protocol);
    }
}
  1. 拷贝生成thrift文件到thrift.consumer工程目录内
cd gen-java #进入生成的Thrift目录
cp -r ./ ../thrift.consumer/src/main/java #拷贝进thrift.consumer工程目录内
  1. 暴露一个HTTP接口 来调用sayHello方法。
package com.kabai.controller;

import com.kabai.thrift.User;
import com.kabai.thrift.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @Autowired
    private UserService.Client userServiceClient;

    @GetMapping("/user/{id}")
    public User getUserById(@PathVariable int id) {
        try {
            return userServiceClient.getUserById(id);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

项目启动

确认服务环境

  • jdk:jdk17
  • maven:3.9.4

依次启动

  • Consul
  • service-provider
  • service-consumer

编译、打包、运行

  • 运行Consul
/root/consul agent -dev -client=0.0.0.0
  • thrift.provider
jdk17
mvn3.9
mvn spring-boot:run

compressed_WX20240606-224907@2x.png

  • service.consumer
jdk17
mvn3.9
mvn spring-boot:run

compressed_WX20240606-224926@2x.png

Consul Dashboard

http://60.35.xx.xx:8500/ui

compressed_WX20240606-224447@2x.png

浏览器访问测试接口

http://localhost:8280/user/11

compressed_WX20240606-224514@2x.png