# consul
**Repository Path**: tangcco/consul
## Basic Information
- **Project Name**: consul
- **Description**: springcloud注册中心consul
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2021-01-28
- **Last Updated**: 2022-06-23
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
---
typora-copy-images-to: img
---
### 一、什么是Consul?
`Consul`是HashiCorp公司推出的开源工具,Consul由Go语言开发,部署起来非常容易,只需要极少的可执行程序和配置文件,具有绿色、轻量级的特点。`Consul`是`分布式`的、`高可用`的、 `可横向扩展`的用于实现分布式系统的服务发现与配置。
#### Consul具有哪些特点?
- 服务发现(Service Discovery):`Consul`提供了通过DNS或者HTTP接口的方式来注册服务和发现服务。一些外部的服务通过Consul很容易的找到它所依赖的服务。
- 健康检查(Health Checking):Consul的Client可以提供任意数量的健康检查,既可以与给定的服务相关联(“webserver是否返回200 OK”),也可以与本地节点相关联(“内存利用率是否低于90%”)。操作员可以使用这些信息来监视集群的健康状况,服务发现组件可以使用这些信息将流量从不健康的主机路由出去。
- Key/Value存储:应用程序可以根据自己的需要使用Consul提供的Key/Value存储。 Consul提供了简单易用的HTTP接口,结合其他工具可以实现动态配置、功能标记、领袖选举等等功能。
- 安全服务通信:Consul可以为服务生成和分发TLS证书,以建立相互的TLS连接。意图可用于定义允许哪些服务通信。服务分割可以很容易地进行管理,其目的是可以实时更改的,而不是使用复杂的网络拓扑和静态防火墙规则。
- 多数据中心:Consul支持开箱即用的多数据中心. 这意味着用户不需要担心需要建立额外的抽象层让业务扩展到多个区域。
#### Consul 架构图

让我们把这幅图分解描述。首先,我们可以看到有两个数据中心,分别标记为“1”和“2”。Consul拥有对多个数据中心的一流支持,这是比较常见的情况。
在每个数据中心中,我们都有客户机和服务器。预计将有三到五台服务器。这在故障情况下的可用性和性能之间取得了平衡,因为随着添加更多的机器,一致性会逐渐变慢。但是,客户端的数量没有限制,可以很容易地扩展到数千或数万。
Consul 实现多个数据中心都依赖于gossip protocol协议。这样做有几个目的:首先,不需要使用服务器的地址来配置客户端;服务发现是自动完成的。其次,健康检查故障的工作不是放在服务器上,而是分布式的。这使得故障检测比单纯的心跳模式更具可伸缩性。为节点提供故障检测;如果无法访问代理,则节点可能经历了故障。
每个数据中心中的服务器都是一个筏对等集的一部分。这意味着它们一起工作来选举单个leader,一个被选中的服务器有额外的职责。领导负责处理所有的查询和事务。事务还必须作为协商一致协议的一部分复制到所有对等方。由于这个需求,当非leader服务器接收到RPC请求时,它会将其转发给集群leader。
#### Consul的使用场景
Consul的应用场景包括服务发现、服务隔离、服务配置:
- 服务发现场景中consul作为注册中心,服务地址被注册到consul中以后,可以使用consul提供的dns、http接口查询,consul支持health check。
- 服务隔离场景中consul支持以服务为单位设置访问策略,能同时支持经典的平台和新兴的平台,支持tls证书分发,service-to-service加密。
- 服务配置场景中consul提供key-value数据存储功能,并且能将变动迅速地通知出去,借助Consul可以实现配置共享,需要读取配置的服务可以从Consul中读取到准确的配置信息。
- Consul可以帮助系统管理者更清晰的了解复杂系统内部的系统架构,运维人员可以将Consul看成一种监控软件,也可以看成一种资产(资源)管理系统。
> 比如:docker实例的注册与配置共享、coreos实例的注册与配置共享、vitess集群、SaaS应用的配置共享、Consul与confd服务集成,动态生成nginx和haproxy配置文件或者Consul结合nginx构建高可用可扩展的Web服务。
### 二、安装
我这里直接安装Consul 最新版本 1.9.2 官网地址:https://www.consul.io/
#### 1. **下载**
我这里进入我的用户目录下面进行下载consul安装压缩包,命令如下:
```shell
wget https://releases.hashicorp.com/consul/1.9.2/consul_1.9.2_linux_amd64.zip
```
#### 2. **解压**
```shell
unzip consul_1.9.2_linux_amd64.zip
```
#### 3. **查看** 安装是否成功
```shell
./consul
```
#### 4. **启动**
```shell
-server 表示是server模式
-bootstrap-expect=3 表示是集群中有3台服务器 bootstrap该模式node可以指定自己作为leader ,如果是非leader可不加该参数
-data-dir=/tmp/consul 目录
-node=n2 该服务器节点名
-bind=127.0.0.1 节点绑定的ip
-ui 非必须 webui的路径 用web来管理consul
-client=0.0.0.0 可以访问的地址
```
开发环境启动命令如下(默认是8500端口):
```shell
./consul agent -dev -client=0.0.0.0 -ui
```
### 三、 部署 Servcie Provider
#### 1. pom.xml
```xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.4.2
cn.kgc.tangcco
idiom-provider
0.0.1-SNAPSHOT
war
idiom-provider
consul project for Spring Boot
15
2020.0.0
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-commons
org.springframework.cloud
spring-cloud-starter-consul-discovery
org.springframework.boot
spring-boot-devtools
runtime
true
mysql
mysql-connector-java
runtime
com.alibaba
druid-spring-boot-starter
1.2.4
org.springframework.boot
spring-boot-configuration-processor
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-tomcat
provided
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
${project.artifactId}
../package
org.projectlombok
lombok
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
```
#### 2. 配置文件
```yaml
server:
port: 8080
servlet:
encoding:
force: true
charset: UTF-8
spring:
application:
name: idiom-provider #应用名称 集群环境下相同
servlet:
multipart:
max-file-size: 50MB # 文件上传大小限制为500kb
max-request-size: 200MB # 请求大小限制为500kb
datasource:
url: jdbc:mysql://47.94.130.233:3306/knowledge?useUnicode=true&characterEncoding=UTF8&useSSL=true&serverTimeZone=Aisa/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
# 下面为连接池的补充设置,应用到上面所有数据源中
# 初始化大小,最小,最大
initial-size: 5
min-idle: 5
max-active: 200
# 配置获取连接等待超时的时间
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1 FROM DUAL
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
max-pool-prepared-statement-per-connection-size: 20
filters: stat,wall,slf4j
use-global-data-source-stat: true
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
stat-view-servlet:
login-username: admin
login-password: 123456
reset-enable: false
url-pattern: /druid/*
allow: 0.0.0.0
#deny:
enabled: true
web-stat-filter:
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
jpa:
database: MySQL
database-platform: org.hibernate.dialect.MySQL8Dialect
show-sql: true
hibernate:
ddl-auto: none
cloud:
consul:
host: 192.168.1.110 # 注册中心地址
port: 8500 # 注册中心端口
discovery:
register: true # 是否注册
instance-id: ${spring.application.name}-01 # 注册实例 id 必须唯一
service-name: ${spring.application.name} # 服务名称
port: ${server.port} # 服务端口
prefer-ip-address: true # 是否使用 ip 注册
ip-address: ${spring.cloud.client.ip-address} # 服务请求 ip
heartbeat:
enabled: true # 是否打开心跳监测
# 度量指标监控与健康检查
management:
endpoints:
web:
exposure:
include: shutdown # 开启 shutdown 端点访问
endpoint:
shutdown:
enabled: true # 开启 shutdown 请求方式必须是post
health:
show-details: ALWAYS
logging:
level:
com.netflix: warn
```
#### 3. pojo类
```java
package cn.kgc.tangcco.pojo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author 李昊哲
* @Description
* @create 2020/12/29 14:22
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Idiom implements Serializable {
private static final long serialVersionUID = 7553935244407585482L;
/**
* 主键ID
*/
private Integer id;
/**
* 成语
*/
private String name;
/**
* 拼音
*/
private String spell;
/**
* 解释
*/
private String content;
/**
* 典故
*/
private String derivation;
/**
* 举例句子
*/
private String samples;
}
```
#### 4. 持久层接口
```java
package cn.kgc.tangcco.repository;
import cn.kgc.tangcco.pojo.Idiom;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* @author 李昊哲
* @Description
* @create 2020/12/29 14:48
*/
@Repository
public interface IdiomRepository extends JpaRepository, JpaSpecificationExecutor {}
```
#### 5. service接口
```java
package cn.kgc.tangcco.service;
import cn.kgc.tangcco.pojo.Idiom;
import org.springframework.data.domain.Page;
/**
* @author 李昊哲
* @Description
* @create 2020/12/29 14:51
*/
public interface IdiomService {
/**
* 分页查询
*
* @param page 查询页码
* @param limit 每页记录数
* @return
*/
public Page finAll(Integer page, Integer limit);
}
```
#### 6. service接口实现类
```java
package cn.kgc.tangcco.service.impl;
import cn.kgc.tangcco.pojo.Idiom;
import cn.kgc.tangcco.repository.IdiomRepository;
import cn.kgc.tangcco.service.IdiomService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
/**
* @author 李昊哲
* @Description
* @create 2021/1/27 11:51
*/
@Service
public class IdiomServiceImpl implements IdiomService {
private final IdiomRepository idiomRepository;
public IdiomServiceImpl(IdiomRepository idiomRepository) {
this.idiomRepository = idiomRepository;
}
@Override
public Page finAll(Integer page, Integer limit) {
return idiomRepository.findAll(PageRequest.of(page - 1, limit));
}
}
```
#### 7. controller
```java
package cn.kgc.tangcco.controller;
import cn.kgc.tangcco.pojo.Idiom;
import cn.kgc.tangcco.service.IdiomService;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 李昊哲
* @Description
* @create 2021/1/27 11:59
*/
@RestController
@RequestMapping(value = "/idiom")
public class IdiomController {
private final IdiomService idiomService;
public IdiomController(IdiomService idiomService) {
this.idiomService = idiomService;
}
@PostMapping(value = "/page")
public Page page(Integer page, Integer limit){
return idiomService.finAll(page,limit);
}
}
```
#### 8. PostMan测试
测试地址:http://localhost:8080/idiom/page
请求方式:POST
请求参数:
| key | value |
| ----- | ----- |
| page | 2 |
| limit | 2 |
```json
{
"content": [
{
"id": 3,
"name": "备而不用",
"spell": "bèi ér bù yòng",
"content": "准备好了,以备急用,眼下暂存不用。",
"derivation": "清·吴趼人《糊涂世界》:“虽说备而不用,到得那时候,听凭兵丁造一句谣言,开上几排枪,那人可就死了不少。”",
"samples": "凡是零星物件,本地买不出,一定要用,或是~的,也都齐全。(清·颐琐《黄绣球》第十七回)"
},
{
"id": 4,
"name": "贝阙珠宫",
"spell": "bèi què zhū gōng",
"content": "用珍珠宝贝做的宫殿。形容房屋华丽。",
"derivation": "战国·楚·屈原《九歌·河伯》:“鱼鳞屋兮龙堂,紫贝阙兮朱宫。”",
"samples": "你看那香焚宝鼎,紫雾漾漾,玉楼金殿,~,便如天宫之景也。(明·无名氏《庆长生》第四折)"
}
],
"pageable": {
"sort": {
"sorted": false,
"unsorted": true,
"empty": true
},
"offset": 2,
"pageSize": 2,
"pageNumber": 1,
"paged": true,
"unpaged": false
},
"last": false,
"totalPages": 15926,
"totalElements": 31851,
"size": 2,
"number": 1,
"sort": {
"sorted": false,
"unsorted": true,
"empty": true
},
"first": false,
"numberOfElements": 2,
"empty": false
}
```
### 四、部署 Servcie Consumer
#### 1. pom.xml
```xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.4.2
cn.kgc.tangcco
idiom-consumer
0.0.1-SNAPSHOT
war
idiom-consumer
consul project for Spring Boot
15
2020.0.0
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-consul-discovery
org.springframework.boot
spring-boot-devtools
runtime
true
org.springframework.boot
spring-boot-configuration-processor
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-tomcat
provided
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
${project.artifactId}
../package
org.projectlombok
lombok
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
```
#### 2. 配置文件
```yaml
server:
port: 80
servlet:
encoding:
force: true
charset: UTF-8
spring:
application:
name: idiom-consumer #应用名称 集群环境下相同
servlet:
multipart:
max-file-size: 50MB # 文件上传大小限制为500kb
max-request-size: 200MB # 请求大小限制为500kb
cloud:
consul:
host: 192.168.1.110 # 注册中心地址
port: 8500 # 注册中心端口
discovery:
register: false # 是否注册
instance-id: ${spring.application.name}-01 # 注册实例 id 必须唯一
service-name: ${spring.application.name} # 服务名称
port: ${server.port} # 服务端口
prefer-ip-address: true # 是否使用 ip 注册
ip-address: ${spring.cloud.client.ip-address} # 服务请求 ip
heartbeat:
enabled: true # 是否打开心跳监测
logging:
level:
com.netflix: warn
```
#### 3. 启动类
```java
package cn.kgc.tangcco;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestOperations;
@SpringBootApplication
public class IdiomConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(IdiomConsumerApplication.class, args);
}
@Bean
@LoadBalanced
public RestOperations restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
```
#### 4. pojo类
```java
package cn.kgc.tangcco.pojo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author 李昊哲
* @Description
* @create 2020/12/29 14:22
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Idiom implements Serializable {
private static final long serialVersionUID = 7553935244407585482L;
/**
* 主键ID
*/
private Integer id;
/**
* 成语
*/
private String name;
/**
* 拼音
*/
private String spell;
/**
* 解释
*/
private String content;
/**
* 典故
*/
private String derivation;
/**
* 举例句子
*/
private String samples;
}
```
#### 5. service接口
```java
package cn.kgc.tangcco.service;
/**
* @author 李昊哲
* @Description
* @create 2020/12/29 14:51
*/
public interface IdiomService {
/**
* LoadBalancerClient 分页查询
*
* @param page 查询页码
* @param limit 每页记录数
* @return
*/
public String finAllByLoadBalancerClientAnnotation(Integer page, Integer limit);
}
```
#### 6. service接口实现类
```java
package cn.kgc.tangcco.service.impl;
import cn.kgc.tangcco.service.IdiomService;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestOperations;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
/**
* @author 李昊哲
* @Description
* @create 2021/1/27 18:50
*/
@Service
public class IdiomServiceImpl implements IdiomService {
private final DiscoveryClient discoveryClient;
// Ribben 负载均衡器
private final LoadBalancerClient loadBalancerClient;
private final RestOperations restTemplate;
public IdiomServiceImpl(DiscoveryClient discoveryClient, LoadBalancerClient loadBalancerClient, RestOperations restTemplate) {
this.discoveryClient = discoveryClient;
this.loadBalancerClient = loadBalancerClient;
this.restTemplate = restTemplate;
}
@Override
public String finAllByLoadBalancerClientAnnotation(Integer page, Integer limit) {
String url = "http://idiom-provider/idiom/page";
HttpHeaders headers = new HttpHeaders();
// 请勿轻易改变此提交方式,大部分的情况下,提交方式都是表单提交
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// 封装参数,千万不要替换为Map与HashMap,否则参数无法传递
MultiValueMap params = new LinkedMultiValueMap<>();
// 也支持中文
params.add("page", page);
params.add("limit", limit);
HttpEntity> requestEntity = new HttpEntity<>(params, headers);
// 执行HTTP请求
ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, new ParameterizedTypeReference<>() {
});
// 输出结果
return response.getBody();
}
}
```
#### 7. controller
```java
package cn.kgc.tangcco.controller;
import cn.kgc.tangcco.service.IdiomService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 李昊哲
* @Description
* @create 2021/1/27 11:59
*/
@RestController
@RequestMapping(value = "/idiom")
public class IdiomController {
private final IdiomService idiomService;
public IdiomController(IdiomService idiomService) {
this.idiomService = idiomService;
}
@GetMapping(value = "/finAllByLoadBalancerClientAnnotation")
public String finAllByLoadBalancerClientAnnotation(
@RequestParam(name = "page",defaultValue = "1",required = true) Integer page,
@RequestParam(name = "limit",defaultValue = "2",required = true) Integer limit){
return idiomService.finAllByLoadBalancerClientAnnotation(page,limit);
}
}
```
#### 8. PostMan测试
测试地址:http://localhost/idiom/finAllByLoadBalancerClientAnnotation
请求方式:GET
请求参数:
| key | value |
| ----- | ----- |
| page | 2 |
| limit | 2 |
```json
{
"content": [
{
"id": 3,
"name": "备而不用",
"spell": "bèi ér bù yòng",
"content": "准备好了,以备急用,眼下暂存不用。",
"derivation": "清·吴趼人《糊涂世界》:“虽说备而不用,到得那时候,听凭兵丁造一句谣言,开上几排枪,那人可就死了不少。”",
"samples": "凡是零星物件,本地买不出,一定要用,或是~的,也都齐全。(清·颐琐《黄绣球》第十七回)"
},
{
"id": 4,
"name": "贝阙珠宫",
"spell": "bèi què zhū gōng",
"content": "用珍珠宝贝做的宫殿。形容房屋华丽。",
"derivation": "战国·楚·屈原《九歌·河伯》:“鱼鳞屋兮龙堂,紫贝阙兮朱宫。”",
"samples": "你看那香焚宝鼎,紫雾漾漾,玉楼金殿,~,便如天宫之景也。(明·无名氏《庆长生》第四折)"
}
],
"pageable": {
"sort": {
"sorted": false,
"unsorted": true,
"empty": true
},
"offset": 2,
"pageSize": 2,
"pageNumber": 1,
"paged": true,
"unpaged": false
},
"last": false,
"totalPages": 15926,
"totalElements": 31851,
"size": 2,
"number": 1,
"sort": {
"sorted": false,
"unsorted": true,
"empty": true
},
"first": false,
"numberOfElements": 2,
"empty": false
}
```
### 五、集群
#### 1. 创建数据存储目录
```shell
mkdir ~/consuldata
```
#### 2. 启动server
```shell
./consul agent -server -bind=192.168.1.111 \
-client=0.0.0.0 -ui \
-bootstrap-expect=3 \
-data-dir=~/consuldata \
-node=server01 \
```
```shell
./consul agent -server -bind=192.168.1.112 \
-client=0.0.0.0 -ui \
-bootstrap-expect=3 \
-data-dir=~/consuldata \
-node=server02 \
-join=192.168.1.111
```
```shell
./consul agent -server -bind=192.168.1.113 \
-client=0.0.0.0 -ui \
-bootstrap-expect=3 \
-data-dir=~/consuldata \
-node=server03 \
-join=192.168.1.111
```
参数解释:
```
-bootstrap-expect=:集群期望的节点数,只有节点数量达到这个值才会选举leader。
-server: 运行在server模式
-client=:consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服务,如果你要对外提供服务改成0.0.0.0
-data-dir=:指定数据目录,其他的节点对于这个目录必须有读的权限
-node=:指定节点的名称
-bind=:为该节点绑定一个地址,默认为0.0.0.0,即主机IP
-config-dir=:指定配置文件,定义服务,默认所有.json结尾的文件都会被载入。
-enable-script-checks=true:设置检查服务为可用
-datacenter=: 数据中心名称,
-join=:加入到已有的集群中
-ui:使能内置的静态web UI服务器
-ui-dir=:指向web UI资源的路径,此路径必须可读。
-retry-join=:要join的server IP
-retry-interval=:尝试join网络的时间间隔
-rejoin:忽略leave重新join
-log-level=:agent log level
```
#### 3. 指定leader
```shell
./consul join 192.168.1.111
```
#### 4. 启动client
```shell
mkdir ~/consuldata
```
```shell
./consul agent -bind=192.168.1.110 \
-client=0.0.0.0 -ui \
-data-dir=~/consuldata \
-node=client \
-join=192.168.1.111
```
#### 5. 启动provider集群
```shell
java -jar idiom-provider-01.war --server.port=10001
java -jar idiom-provider-02.war --server.port=10002
```
#### 6. 启动consumer
```java
java -jar idiom-consumer.war --server.port=8080
```
#### 7. PostMan测试
请求地址:http://192.168.1.110:8080/idiom/finAllByLoadBalancerClientAnnotation
请求方式:GET
请求参数:
| key | value |
| ----- | ----- |
| page | 2 |
| limit | 2 |
返回结果:
```json
{
"content": [
{
"id": 3,
"name": "备而不用",
"spell": "bèi ér bù yòng",
"content": "准备好了,以备急用,眼下暂存不用。",
"derivation": "清·吴趼人《糊涂世界》:“虽说备而不用,到得那时候,听凭兵丁造一句谣言,开上几排枪,那人可就死了不少。”",
"samples": "凡是零星物件,本地买不出,一定要用,或是~的,也都齐全。(清·颐琐《黄绣球》第十七回)"
},
{
"id": 4,
"name": "贝阙珠宫",
"spell": "bèi què zhū gōng",
"content": "用珍珠宝贝做的宫殿。形容房屋华丽。",
"derivation": "战国·楚·屈原《九歌·河伯》:“鱼鳞屋兮龙堂,紫贝阙兮朱宫。”",
"samples": "你看那香焚宝鼎,紫雾漾漾,玉楼金殿,~,便如天宫之景也。(明·无名氏《庆长生》第四折)"
}
],
"pageable": {
"sort": {
"sorted": false,
"unsorted": true,
"empty": true
},
"offset": 2,
"pageSize": 2,
"pageNumber": 1,
"paged": true,
"unpaged": false
},
"last": false,
"totalPages": 15926,
"totalElements": 31851,
"size": 2,
"number": 1,
"sort": {
"sorted": false,
"unsorted": true,
"empty": true
},
"first": false,
"numberOfElements": 2,
"empty": false
}
```
#### 8. ui展示



#### 10. 常用命令如下:
1)information
```
./consul info
```
可以在raft:stat看到此节点的状态是Fllower或者leader
2)列出集群成员
```
./consul members
```
3)新加入一个节点有几种方式;
这种方式,重启后不会自动加入集群
```
./consul join 192.168.1.202
```
在启动的时候使用-join指定一个集群
```
./consul agent -ui -data-dir /data/consul0 -node=cn4 -bind=192.168.1.198 -config-dir /etc/consul.d -enable-script-checks=true -datacenter=dc1 -join 192.168.1.202
```
使用-startjoin或-rejoin
```
./consul agent -ui -data-dir /data/consul0 -node=cn4 -bind=192.168.1.198 -config-dir /etc/consul.d -enable-script-checks=true -datacenter=dc1 -rejoin
```
4)consul默认绑定的端口
```
8300:Server RPC address
8301:lan gossip,the Serf LAN port
8302:wan gossip,the Serf WAN port
8500:http api端口
8501:httpsapi端口,默认disabled
8502:gRPCapi端口,默认disabled
8600:DNS服务端口
21000:Sidecar Proxy Min: Inclusive min port number to use for automatically assigned sidecar service registrations.
21255:Sidecar Proxy Max: Inclusive max port number to use for automatically assigned sidecar service registrations.
```
5)健康检查
check使用来做服务的健康检查的,可以拥有多个,也可以不使用支持多种方式检查。check必须是script或者TTL类型的,如果是script类型则script和interval变量必须被提供,如果是TTL类型则ttl变量必须被提供。script是consul主动去检查服务的健康状况,ttl是服务主动向consul报告自己的状况。
**script check:**
```
{
"check":{
"id": mutil-memory,
"name": "memory utilization",
"tags": ["system"],
"script": "/etc/init.d/check_memory.py",
"interval": "10s",
"timeout": "1s"
}
}
```
**http check:**
```
{
"check": {
"id": "api",
"name": "HTTP API 500",
"http": "http://loclhost:500/health",
"interval": "10s",
"timeout": "1s"
}
}
```
**tcp check:**
```
{
"check": {
"id": "ssh",
"name": "ssh TCP 26622",
"tcp": "localhost:26622",
"interval": "10s",
"timeout": "1s"
}
}
```
**ttl check:**
```
{
"check": {
"id": "web-app",
"name": "Web APP status",
"notes": "Web APP does a curl internally every 10 seconds",
"ttl": "30s"
}
}
```
**6)服务注册**
注册服务有三种方式。
**通过配置文件的方式静态注册**
保存json配置文件到consul配置目录,重启consul,并将配置文件的路径给consul。
**通过HTTP API接口来动态注册**
直接调用/v1/agent/service/register接口注册即可,需要注意的是:http method为PUT提交方式,如:
```
curl -X PUT -d '{"id": "jetty","name": "jetty","address": "192.168.1.200","port": 8080,"tags": ["dev"],"checks": [{"http": "http://192.168.1.104:9020/health","interval": "5s"}]}' http://192.168.1.100:8500/v1/agent/service/register
```
注意:这种方式,和上面的注册方式有一点不一样,body的参数,是上面service的值。
**使用程序实现服务的注册和发现(Java)**
**7)查询服务**
```
#consul catalog services
consul
edgex-core-command
edgex-core-data
edgex-core-metadata
edgex-export-client
edgex-export-distro
edgex-mongo
edgex-support-logging
edgex-support-notifications
edgex-support-rulesengine
edgex-support-scheduler
```
或者通过httpapi查询:
```
#curl 127.0.0.1:8500/v1/catalog/services
#curl 127.0.0.1:8500/v1/catalog/service/edgex-mongo
```
查询agent上所有服务:
```
#curl 127.0.0.1:8500/v1/agent/services
```
**8)删除服务**
### 六、Consul 开机自启动
#### 1. 路径/usr/lib/systemd/system/,新建一个service命名为,consul.service
```
[Unit]
Description=consul-service
After=network.target
[Service]
Type=forking
PIDFile=/run/consul-service.pid
ExecStart=/usr/service/consul.start.sh
ExecReload=/bin/kill -SIGHUP $MAINPID
ExecStop=/bin/kill -SIGINT $MAINPID
[Install]
WantedBy=multi-user.target graphical.target
1234567891011121314
```
上面的ExecStart 是启动的脚本,我之前把consul 是安装在/user/service 下面,
#### 2. 创建启动脚本
我们再service 目录中创建Consul开机自启动的脚本文件consul.start.sh
```
#!/bin/bash
/usr/service/consul agent -server -bootstrap-expect 1 -node=127.0.0.1 -data-dir=/usr/service/data/ -log-file=/usr/service/log/consul_log-$(date +%Y-%m-%d--%H-%M) -bind=127.0.0.1
12
```
#### 3. 重新加载配置
```
systemctl daemon-reload
```
#### 4. 设置开机自启动
```
systemctl enable consul.service
```
Consul 启动
```
systemctl start consul
```
Consul 停止
```
systemctl stop consul
```
上面创建开机自启动脚本实践的时候大家可能会发现 通过systemctl start consul 无法启动问题,这时候可以通过status 来查询状态,命令如下
```
systemctl status consul
```
查询创建的自启动脚本执行过程中出现`code=exited, status=203/EXEC`异常错误信息,这个信息一般有如下几个原因造成:
- 错误的脚本路径
- 脚本的权限无效
- 服务用户没有读取脚本的权限
- 脚本未标记为可执行