There is a registry in the system, there is a configuration center, isn’t there a versatile player to save trouble? Yes, of course there is.

Previous articles covered Eureka and Spring Cloud Config, today we introduce an all-rounder “Consul”. HashiCorp is a tool for service discovery and service configuration. Developed with go language, it has good portability. Included in Spring Cloud, Eureka has stopped developing new versions and is more likely to let developers use Consul to register discovery as a service.

Consul provides the following features:

Service discovery

Consul makes service registration and service discovery (via DNS and HTTP interfaces) much easier, even for external service registrations such as SaaS.

Fault detection

With health checks, service discovery prevents requests from being routed to unhealthy hosts and makes it easy for services to disconnect (no longer being served).

Multi-data center

Consul does not require complex configuration to easily scale out to multiple data centers, find services in other data centers, or simply request services from the current data center.

The key value store

Flexible key-value storage, provides dynamic configuration, feature marking, collaboration, leader election and other functions, and realizes real-time notification of configuration changes through long polling.

Spring Cloud Consul automatically configures and further encapsulates Consul.

Spring Cloud Consul replaces the existing Spring Cloud Eureka, which is used as a service registration discovery framework. In addition, the development of Eureka 2.x version has been stopped, and the official Spring Cloud suggests using Spring Cloud Consul instead. Of course, it doesn’t matter if Eureka has been used in the project, as Eureka is stable enough. Normal use without any problems.

Spring Cloud Consul can be used as a configuration center instead of Spring Cloud Config.

Spring Cloud Consul is primarily used for service registration discovery and is officially proposed as an alternative to Eureka, so it certainly has advantages that Eureka or other frameworks do not. Here’s how it compares to other service discovery methods (from the Web):

The function point euerka Consul zookeeper etcd
Service health check Can match support Service status, memory, hard disk, etc (weak) long connection, keepalive Connect the heart
Multi-data center support
Kv storage service support support support
consistency raft paxos raft
cap Ap (High availability, partition fault tolerance) Ca (Data consistency, high availability) cp cp
Using interfaces (multilingual capability) HTTP (sidecars) Supports HTTP and DNS The client http/grpc
Watch support Long polling/ most increments is supported Full/Long polling is supported support Support long polling
Their monitoring metrics metrics metrics
security acl /https acl HTTPS support (weak)
Spring cloud integration Have support Have support Have support Have support

Consul uses raft algorithm to ensure data consistency, and the benefits are clear, but there are also some sacrifices:

  1. Service registration is a bit slower than Eureka. Raft protocol in Consul requires that more than half of the nodes have been successfully written to be considered registered.
  2. When the Leader fails, the entire Consul is unavailable during a re-election, ensuring strong consistency but sacrificing availability.

Consul installation and launch

Different from Eureka, Consul need independent installation, can go to the website (www.consul.io/downloads.h…

Consul provides a list of parameters that can be executed on the command line. Consul provides a Web UI interface to view the configuration by default. You can access the Web UI console by accessing port 8500 of the server.

Consul agent-dev during the consul development process, you can run the consul agent-dev command to enable the consul development mode. After successfully enabling consul, access localhost:8500 to view all services on consul. The diagram below:

For more information on how to deploy in a build environment, you can search for more information on how to use Spring Cloud Consul.

Implementing the service provider

1. Reference spring-cloud-consul

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-all</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-consul-dependencies</artifactId>
            <version>2.1.0. M2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
Copy the code

2. Set consul configuration as follows in the bootstrap.yml configuration file:

spring:
  cloud:
    consul:
      discovery:
        service-name: consul-provider  # service provider name
      host: localhost                  Consul's service address
      port: 8500					   # # consul port
Copy the code

In the application.yml configuration file, set the following parameters:

spring:
  application:
    name: consul-provider
server:
  port: 5000

endpoints:
  health:
    sensitive: false
  restart:
    enabled: true
  shutdown:
    enabled: true

management:
  security:
    enabled: false
Copy the code

4. Add a RestController and write two test service methods

@RestController
@Slf4j
public class HelloController {

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping(value = "test")
    public String test(a){
        List<String> services = discoveryClient.getServices();
        for(String s : services){
            log.info(s);
        }
        return "hello spring cloud!";
    }

    @GetMapping(value = "nice")
    public String nice(a){
        List<String> services = discoveryClient.getServices();
        for(String s : services){
            log.info("gogogo" + s);
        }
        return "nice to meet you!"; }}Copy the code

5, Spring Boot boot class

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

The @enableDiscoveryClient annotation indicates that this is a client.

Start the service provider and open http://localhost:8500 to see the service

## Realize service consumers

1, reference the related Maven package, in addition to reference the same package as the service provider above, also reference openFeign

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Copy the code

2. Bootstrap. yML configuration. As a service consumer, the Settings are not registered with Consul

spring:
  cloud:
    consul:
      discovery:
        register: false
Copy the code

3. Application. Yml configuration

spring:
  application:
    name: consul-customer
server:
  port: 5001

endpoints:
  health:
    sensitive: false
  restart:
    enabled: true
  shutdown:
    enabled: true

management:
  security:
    enabled: false
Copy the code

4. Project startup

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class Application {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(a) {
        return new RestTemplate();
    }

    public static void main(String[] args) { SpringApplication.run(Application.class, args); }}Copy the code

Use the @enableDiscoveryClient annotation to indicate that as a service client, @enableFeignClients enables openFeign.

5. Create an openFeign service interface

@FeignClient(value = "consul-provider")
public interface IHelloService {

    @RequestMapping(value = "/hello")
    String hello(a);

    @RequestMapping(value = "nice")
    String nice(a);
}
Copy the code

Two RESTful interface addresses provided by the service provider

Implement a RestController to access services exposed by the service provider

@RestController
public class ConsumerController {

    @Autowired
    private LoadBalancerClient loadBalancer;

    @Autowired
    private DiscoveryClient discoveryClient;


    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IHelloService helloService;

    private final static String SERVICE_NAME = "consul-provider";


    /** * Use the normal RestTemplate method to access the service **@return* /
    @GetMapping(value = "test")
    public Object test(a) {
        String result = restTemplate.getForObject("http://"+SERVICE_NAME + "/test", String.class);
        System.out.println(result);
        return result;
    }

    /** * Use openFeign to access the service **@return* /
    @GetMapping(value = "feign")
    public Object feign(a) {
        String s = helloService.nice();
        return s;
    }
    

    /** * get all service instances **@return* /
    @GetMapping(value = "/services")
    public Object services(a) {
        return discoveryClient.getInstances(SERVICE_NAME);
    }

    /** * Select a service from all services (polling) */
    @GetMapping(value = "/choose")
    public Object choose(a) {
        returnloadBalancer.choose(SERVICE_NAME).getUri().toString(); }}Copy the code

Start the consumer application and then access the corresponding RESTful interface to get the corresponding results.

Implement a highly available service provider

It is better not to have a single point of microservice online. Then configure two service providers to start the same service as long as the service-name is the same.

1. The bootstrap.yml configuration remains unchanged

spring:
  cloud:
    consul:
      discovery:
        service-name: consul-provider
      host: localhost
      port: 8500
Copy the code

2. Change application.yml to the following configuration

spring:
  profiles:
    active: consul-provider1
endpoints:
  health:
    sensitive: false
  restart:
    enabled: true
  shutdown:
    enabled: true

management:
  security:
    enabled: false

---
spring:
  profiles: consul-provider1
  application:
    name: consul-provider1

server:
  port: 5000

---
spring:
  profiles: consul-provider2
  application:
    name: consul-provider2

server:
  port: 5002
Copy the code

3. Add vm parameters after startup. Add parameters separately:

-Dspring.profiles.active=consul-provider1

-Dspring.profiles.active=consul-provider2

Start the service provider Consul-provider on port 5000 and port 5002 respectively

4. Finally access the RESTful interface address of the consumer, and you can see the service instance invoked by each request in the background of the service provider.

Used as a configuration center

As we know, Spring Cloud Config provides the configuration center function, but it needs to cooperate with Git, SVN or external storage (such as various databases). Therefore, since Consul is used, the configuration center function provided by Consul can be used. No additional Git, SVN, or database is required.

Next, take a quick look at how Spring Cloud Consul can be used as a configuration hub. Consul supports configuration files in YAML and Properties formats. The yamL format is used as an example in this example.

1. Reference the relevant Maven package

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Copy the code

2. Bootstrap. yml configuration, where parameters related to config are mainly set

spring:
  cloud:
    consul:
      config:
        enabled: true    Enable configuration center
        format: yaml     # set the configuration format to YAML
        data-key: mysql_config } # key in consul key/value
        prefix: config         The outermost directory in which the configuration file resides
        defaultContext: consul-config  # parent directory of mysql_config
      discovery:
        register: false
Copy the code

On consul, the configuration in key/ Value is as follows:

3. Application. yml Configuration file contents

spring:
  application:
    name: consul-config
server:
  port: 5008

endpoints:
  health:
    sensitive: false
  restart:
    enabled: true
  shutdown:
    enabled: true

management:
  security:
    enabled: false
Copy the code

Define the configuration file entity class, specify the @ConfigurationProperties annotation, and specify that the prefix is mysql, which is the top-level key in the key/ Value configuration file.

@Component
@ConfigurationProperties(prefix = "mysql")
public class MySqlComplexConfig {

    public static class UserInfo{

        private String username;

        private String password;

        public String getUsername(a) {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword(a) {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        @Override
        public String toString(a) {
            return "UserInfo{" +
                    "username='" + username + '\' ' +
                    ", password='" + password + '\' ' +
                    '} '; }}private String host;

    private UserInfo user;


    public String getHost(a) {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public UserInfo getUser(a) {
        return user;
    }

    public void setUser(UserInfo user) {
        this.user = user; }}Copy the code

5. Create a RestController to retrieve the output value

@RestController
@Slf4j
public class ConfigController {

    @Autowired
    private MySqlConfig mySqlConfig;

    @Autowired
    private MySqlComplexConfig mySqlComplexConfig;


    @GetMapping(value = "mysqlhost")
    public String getMysqlHost(a){
        return mySqlConfig.getHost();
    }

    @GetMapping(value = "mysqluser")
    public String getMysqlUser(a){
        log.info(mySqlComplexConfig.getHost());
        MySqlComplexConfig.UserInfo userInfo = mySqlComplexConfig.getUser();
        returnuserInfo.toString(); }}Copy the code

6. Finally, start the application and access the RestController RESTful interface to view the content of the configuration file.

Compared to Spring Cloud Config, Consul updates immediately after configuration changes are made in the console, eliminating the need to combine with Spring Cloud Bus and the like.