SpringBoot系列: 使用 consul 作為服務注冊組件


本文基本上摘自純潔的微笑的博客 http://www.ityouknow.com/springcloud/2018/07/20/spring-cloud-consul.html . 感謝作者的付出. 


=============================
服務注冊基礎組件選擇
=============================
在服務注冊這個環節, 業界有很多組件可供選擇, 主要有:
1. Spring Cloud Eureka
Spring Cloud Eureka 是 Spring Cloud Netflix 項目下的服務治理模塊, 而 Sping Cloud Netflix 是 Spring Cloud 的子項目之一, 主要是對 Netflix 公司開源的一些產品的封裝, 這包括, 服務發現 (Eureka), 智能路由 (Zuul), 客戶端負載均衡 (Ribbon), 斷路器 (Hystrix).
2. Consul
Consul 主要用於服務注冊, 分布式配置管理等領域, 對於服務注冊方面它是一個一站式的解決方案, 提供健康檢查, DNS 域名解析等功能. Spring Cloud 也有基於 consul 的服務治理子項目 Spring Cloud Consul, 主要提供服務注冊和分布式配置管理功能.
3. Zookeeper
Zookeeper 也是一個流行的開源項目, 主要用於分布式事務協調, 服務注冊, 分布式配置管理等領域. Spring Cloud 也有基於 zookeeper 的服務治理子項目 Spring Cloud Zookeeper, 主要提供服務注冊和分布式配置管理功能.

我的推薦: Consul + Spring Cloud Consul. 原因有:
1. Consul 勝出 Eureka 的地方: Consul 更知名, 更流行, Consul 集群運維成本自然低了不少.
2. Consul 勝出 Zookeeper 的地方: ZooKeeper 的知名度要比 Consul 高, 但 Consul 在流行程度上也不會差很多. 回到服務注冊這個領域, Consul 比 ZooKeeper 更加全面更完善, 健康檢查和 DNS 服務是拿來即用的.


=============================
Demo 整體設計 和 Consul 啟動
=============================
服務生產者項目將向 consul 注冊自己, 另一個項目是服務消費者. 整個架構包括:
1. 服務生產者項目部署兩份, 這樣能提供要給 HA
2. 服務消費者項目, 服務消費者能自動應用負載均衡策略向兩個生產者服務發出請求.
3. consul 的作用, 不管是 HA 還是 LB, 都是需要 consul 提供的 DNS 支持.

服務生產者項目的要點:
1. 主程序加上 @EnableDiscoveryClient 注解

在消費項目主要用到了下面 3 個接口/類:
1. DiscoveryClient 接口, 用於服務發現操作, 自動注入的實際類型為 CompositeDiscoveryClient 類.
2. LoadBalancerClient 接口, 用於負載均衡,自動注入的實際類型為 RibbonLoadBalancerClient 類.
3. RestTemplate 類, 用於進行 http 請求, 有兩種方式實現負載均衡. 一個方法是在發出web請求的時候, 傳入 LoadBalancerClient.getServiceId() url; 另一個方法是直接創建一個負載均衡的 RestTemplate實例, web 請求的 url 格式就可以泛化為 http://service-producer/your_api .


=============================
Consul 啟動
=============================
consul server 直接使用 consul agent --dev 命令, 啟動一個測試 server 即可, 得到兩個重要的訪問端口.
輸出有:
Started DNS server 127.0.0.1:8600 (tcp)
Started HTTP server on 127.0.0.1:8500 (tcp)


=============================
spring-cloud-starter-consul-discovery 一些重要屬性
=============================

# 直接指定服務的 consul service id(即 instance id).
# 默認情況下為 spring.application.name + server.port, 如果在多個服務器上同一個服務, 因為應用名和端口都一致, 會導致service id 會重復, 所以一般情況都需要引入一個隨機數避免重復 . 
spring.cloud.consul.discovery.instance-id=${spring.application.name}-${random.value}

# 指定服務的 consul service name 
spring.cloud.consul.discovery.service_name=some_name

# consul 服務器主機名 
spring.cloud.consul.discovery.hostname=your_host

# consul 服務器端口
spring.cloud.consul.discovery.port=8500

# 維護 tags
$ 下面示例的 tag map 是:  foo->bar 和 baz->baz
spring.cloud.consul.discovery.tags:foo=bar, baz

# 是否啟用服務發現 
spring.cloud.consul.discovery.enabled=true 

# 使用 consul 服務器 IP, 而不是 hostname, 需要搭配 prefer-ip-address 屬性
spring.cloud.consul.discovery.ip-address=127.0.0.1

# 在注冊時使用 consul IP, 而不是 hostname
spring.cloud.consul.discovery.prefer-ip-address=false

#設定 consul acl token 值
spring.cloud.consul.discovery.acl-token=4efb1523-76a3-f476-e6d8-452220593089

# 健康檢查的頻率, 默認 10 秒
spring.cloud.consul.discovery.health-check-interval=10s

# actuator 健康檢查的 url 路徑
# 默認為 為${management.endpoints.web.base-path} +/health
spring.cloud.consul.discovery.health-check-path=
 
# 自定義健康檢查的 url(適合於不適用 actuator 的場景)
spring.cloud.consul.discovery.health-check-url=


=============================
服務生產者項目 1
=============================
一個簡單的 Restful Service 項目.


----------------------------
pom.xml
----------------------------
項目使用 spring starter 向導生成, 增加 actuator 和 consul-discovery 依賴.
1. actuator 是必需的, 用於 consul 監控 web 項目的健康狀態.
2. spring-cloud-starter-consul-discovery 也是必需的, Consul 服務發現的 starter jar 包.

pom.xml 重要內容有:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR2</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency> 
    </dependencies>

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

----------------------------
主入口程序 SvcProducerApplication
----------------------------
在主入口程序類上增加 @EnableDiscoveryClient 注解后, 自動完成服務注冊.

@SpringBootApplication
@EnableDiscoveryClient
public class SvcProducerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SvcProducerApplication.class, args);
    }
}

 


----------------------------
Rest 服務類 HelloController
----------------------------
很簡單的一個服務類, 提供一個 Restful API.

public class HelloController {
    private String port="8080" ;

    @RequestMapping("/hello")
    public String hello() {
        return "hello consul from "+this.port;
    }
}


----------------------------
application.properties 文件
----------------------------
設定 consul 的 http 注冊 IP 和端口 (8500), 並設定 consul service id 和 consul service name.
consul service id 是必需的, 生成的規則: spring.application.name+[-[server.port]]
consul service name 不是必需的, 但往往需要配置. 設定屬性為: spring.cloud.consul.discovery.serviceName, 不設定的話, name 值同 Id 值.
consul service name 和 consul service id 的簡單類比, consul service name 相當於 DNS 的域名, id 相當於 DNS A 記錄.

文件的內容:

spring.application.name=spring-cloud-consul-producer
server.port=8080 
spring.cloud.consul.discovery.serviceName=service-producer
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500


啟動后將有下面的服務注冊日志:
Registering service with consul: NewService{id='spring-cloud-consul-producer-8080', name='service-producer', tags=[secure=false], address='admin-PC', port=8080, enableTagOverride=null, check=Check{script='null', interval='10s', ttl='null', http='http://admin-PC:8080/actuator/health', tcp='null', timeout='null', deregisterCriticalServiceAfter='null', tlsSkipVerify=null, status='null'}, checks=null}

 



=============================
服務生產者項目 2
=============================
服務生產者項目 2 和項目 1 其實應該完全一致, 因為我們想要在一台電腦上部署, 所以修改一下對應端口即可.

 

=============================
服務消費者項目
=============================

----------------------------
pom.xml
----------------------------
pom.xml 同 服務生產者項目. 需要說明的是:
1. actuator 對於服務消費者來講, 並不是必需的.
2. spring-cloud-starter-consul-discovery 是必需的, Consul 服務發現的 starter jar 包.


----------------------------
application.properties 文件
----------------------------
只需要指定 consul 的服務 hostname 和端口即可. 

spring.application.name=spring-cloud-consul-consumer
server.port=8503
spring.cloud.consul.host=127.0.0.1
spring.cloud.consul.port=8500


----------------------------
消費類文件 ServiceController.java
----------------------------

在消費代碼中, 主要用到了下面 3 個接口/類:
1. DiscoveryClient 接口, 用於服務發現操作, 自動注入的實際類型為 CompositeDiscoveryClient 類.
2. LoadBalancerClient 接口, 用於負載均衡,自動注入的實際類型為 RibbonLoadBalancerClient 類.
3. RestTemplate 類, 用於進行 http 請求, 有兩種方式實現負載均衡. 一個方法是在發出web請求的時候, 傳入 LoadBalancerClient.getServiceId() url; 另一個方法是直接創建一個負載均衡的 RestTemplate實例, web 請求的 url 格式就可以泛化為 http://service-producer/your_api .

@RestController
public class ServiceController {
    @Autowired
    private LoadBalancerClient loadBalanacer;
    @Autowired
    private DiscoveryClient discoverClient;

    /**
     * 獲取所有的服務
     */
    @RequestMapping("/services")
    public Object services() {
        return discoverClient.getInstances("service-producer");
    }

    @RequestMapping("/discover")
    public Object discover() {
        return loadBalanacer.choose("service-producer").getUri().toString();
    }
}


@RestController
class HelloController {
    @Autowired
    private LoadBalancerClient loadBalancer;

    /*
     * 聲明一個負載均衡的 RestTemplate bean
     * */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    /*
     * 自動注入一個負載均衡的 RestTemplate
     * */
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/call")
    public String call() {
        ServiceInstance serviceInstance = loadBalancer.choose("service-producer");
        System.out.println("Hostname:" + serviceInstance.getUri());
        System.out.println("service name:" + serviceInstance.getServiceId());

        //String serviceResult = new RestTemplate().getForObject(serviceInstance.getUri().toString() + "/hello",String.class);
        String serviceResult=restTemplate.getForObject("http://service-producer/hello",String.class);
        return serviceResult ;
    }
}

 

 


=============================
參考
=============================
springcloud(十三):注冊中心 Consul 使用詳解
http://www.ityouknow.com/springcloud/2018/07/20/spring-cloud-consul.html
https://www.cnblogs.com/ityouknow/p/9340591.html

Spring Cloud Finchley 版中 Consul 多實例注冊的問題處理
http://blog.didispace.com/Spring-Cloud-Finchley-Consul-InstanceId/

Spring Cloud 構建微服務架構:服務注冊與發現(Eureka、Consul)【Dalston 版】
http://blog.didispace.com/spring-cloud-starter-dalston-1/

https://howtodoinjava.com/spring-cloud/consul-service-registration-discovery/

使用 Spring Cloud Consul 實現服務的注冊和發現
https://blog.csdn.net/mn960mn/article/details/51775212

Spring Cloud(二) Consul 服務治理實現
https://segmentfault.com/a/1190000012245512

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM