微服务注册中心之Eureka、Zookeeper、Consul

在微服务架构中,注册中心是必不可少的一部分,其主要实现了服务治理功能,本文主要讲述如何使用Eureka、Zookeeper、Consul来作为注册中心,来实现服务治理功能。

1.Eureka

服务发现是基于微服务的体系结构的关键部分之一。尝试手动配置每个客户端或某种形式的约定可能很难做到,而且很可能出问题。Eureka是Netflix服务发现服务器和客户端。可以将服务器配置和部署为高可用性,每个服务器将注册服务的状态复制到其他服务器。

1.1 使用Eureka编写注册中心服务

创建一个maven项目,项目名为eureka-server,在pom文件添加Eureka依赖。

<?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>com.alias</groupId>
        <artifactId>springcloud</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>com.alias</groupId>
    <artifactId>eureka-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eureka-server</name>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
	
    ......
</project>

项目启动类添加@EnableEurekaServer注解

package com.alias.eureka.server;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

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

}

编辑配置文件application,yml

spring:
  application:
    name: eureka-server
server:
  port: 8761

eureka:
  server:
    #自我保护机制关闭
    enable-self-preservation: false
  client:
  	# 由于该应用为注册中心,所以设置为false,就是不向注册中心注册自己
    register-with-eureka: false
    # 由于注册中心是维护服务实例,并不需要检索服务,所以设置为false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  instance:
    hostname: localhost

接下来我们运行EurekaServerApplication就可以启动我们的注册中心了,我们在application.yml配置文件配置的端口是8761,在浏览器访问http://localhost:8761便可以看到Eureka提供的Web控制台。

在这里插入图片描述

1.2 编写服务提供者

创建一个maven项目alias-user,在pom文件中添加相关依赖

<?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>com.alias</groupId>
        <artifactId>springcloud</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>com.alias</groupId>
    <artifactId>alias-user</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>alias-pay</name>
    <description>Demo project for Spring Boot</description>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

编写项目启动类,添加@EnableEurekaClient注解

@SpringBootApplication
@EnableDiscoveryClient
public class AliasOrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(AliasOrderApplication.class, args);
    }

}

创建application.yml文件

server:
  port: 8083
#eureka注册中心配置  eureka.client.service-url.defaultZone地址是我们注册中心的地址。
eureka:
  client:
    service-url:
     defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: alias-order


添加一个controller类,提供给其他服务调用

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @GetMapping("/getOrder")
    public OrderVO getOrder(String userNo) {
        return orderService.getOrder(userNo);
    }
}

/**
 * @author alias
 * @date 2020/3/16 16:26
 */
public interface OrderService {

    /**
     * 通过用户id获取用户
     * @param orderNo
     * @return
     */
    OrderVO getOrder(String orderNo);
}

@Service
public class OrderServiceImpl implements OrderService {

    @Value("${server.port}")
    private String port;

    @Override
    public OrderVO getOrder(String orderNo) {
        OrderVO orderVO = new OrderVO();
        orderVO.setOrderNo(orderNo);
        orderVO.setOrderName("order服务端口:" + port);
        return orderVO;
    }
}

启动AliasOrderApplication服务,可以在控制台看到注册到注册中心的日志:

DiscoveryClient_ALIAS-ORDER/H37BVIYLDSGMOGU:alias-order:8083 - registration status: 204

在eureka的web控制台我们也可以看到新注册的服务信息

eureka服务注册信息

1.3 编写服务消费者

创建服务消费者maven项目alias-pay,pom文件依赖添加和配置文件内容和服务提供者alias-order差不多,只是配置文件的端口和应用名修改了。

这里使用RestTemlpate调用远程http服务。这里我们添加RestTemplate配置。

@Configuration
public class WebConfig {

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

便希望controller类,在业务中调用order服务接口(此处只是模拟调用,至于业务合不合逻辑就不管了,我们只看如果调用其他服务就行了)

@RestController
@RequestMapping("/pay")
public class PayController {

    @Autowired
    private PayService payService;

    @GetMapping("/payOrder")
    public String payOrder(String orderNo, double payMoney) {
        return payService.payOrder(orderNo, payMoney);
    }
}

public interface PayService {

    /**
     * 支付订单
     * @param orderNo
     * @param payMoney
     * @return
     */
    String payOrder(String orderNo, double payMoney);
}

@Service
public class PayServiceImpl implements PayService {

    private static final String INVOKE_URL = "http://ALIAS-ORDER/";
    @Value("${server.port}")
    private String port;

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public String payOrder(String orderNo, double payMoney) {
        OrderVO orderVO = restTemplate.getForObject(INVOKE_URL + "order/getOrder?orderNo=12020222", OrderVO.class);

        return "支付订单:" + orderVO.getOrderName() + ",服务端口:" + port;
    }
}

执行AliasOrderApplication启动消费服务,调用/pay/payOrder接口,看到返回支付订单:order服务端口:8083,服务端口:8081说明调用成功。

至于Eureka健康检查、高可用部署等功能,可自行查阅官方文档

2.Zookeeper

ZooKeeper是用于分布式应用程序的分布式,开放源代码协调服务。它公开了一组简单的原语,分布式应用程序可以基于这些原语来实现用于同步,配置维护以及组和命名的更高级别的服务。它的设计易于编程,并使用了按照文件系统熟悉的目录树结构样式的数据模型

2.1 安装Zookeeper

请参阅安装文档以获取有关如何安装Zookeeper的说明。

2.2 使用Zookeeper进行服务发现

服务发现是基于微服务的体系结构的关键原则之一。尝试手动配置每个客户端或某种形式的约定可能很困难并且很容易出问题。Curator(Zookeeper的Java库)通过Service Discovery Extension提供服务发现。Spring Cloud Zookeeper使用此扩展进行服务注册和发现。

我们基于上面的项目,修改项目的pom文件依赖、还有配置。

  		<!--注释掉spring-cloud-starter-netflix-eureka-client的依赖,添加spring-cloud-starter-zookeeper-discovery依赖-->
		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!--        </dependency>-->

application.yml配置文件修改

#eureka注册中心配置
#eureka:
#  client:
#    service-url:
#      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: alias-pay
    #zookeeper注册中心配置
    cloud:
      zookeeper:
        connect-string: localhost:2181

项目启动类去掉@EnableEurekaClient注解,使用@EnableDiscoveryClient注解。

启动项目,我这里使用zkUI查看注册到zookeeper的节点信息,至于zkUI安装可参考zookeeper可视化工具zkui搭建

kui微服务节点

同样的,我们按照上面的方式修改alias-order配置,启动项目,查看zk节点信息。

zkui多个服务启动节点查看

调用http://localhost:8081/pay/payOrder接口,看到返回支付订单:order服务端口:8083,服务端口:8081说明调用成功。

注意,在pay服务使用RestTemplate调用order服务的时候,我们使用的是服务名来发现服务,这里注册到zookeeper的服务名是小写。自己编写调用时,要注意服务实例名称,否则调用接口时会找不到服务而报错

3.Consul

Consul是一个服务网格解决方案,是一个一个分布式的,高度可用的系统。它提供了一个功能齐全的控制平面,提供服务发现、健康检查、键值存储、安全服务通信、多数据中心等功能。

3.1 安装Consul

安装指南可以参考官方文档,也可以查看本人写的Linux上安装Consul

3.2 启动Consul代理

这里用开发模式下启动consul代理。

$ consul agent -dev
==> Starting Consul agent...
           Version: 'v1.7.2'
           Node ID: '58b5abd3-4071-f5d5-bf6d-d87e0e7fb079'
         Node name: 'alias'
        Datacenter: 'dc1' (Segment: '<all>')
            Server: true (Bootstrap: false)
       Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, DNS: 8600)
      Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)
           Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false

==> Log data will now stream in as it occurs:

    2020-03-18T20:14:44.575+0800 [DEBUG] agent: Using random ID as node ID: id=58b5abd3-4071-f5d5-bf6d-d87e0e7fb079
    2020-03-18T20:14:44.575+0800 [DEBUG] agent.tlsutil: Update: version=1
    2020-03-18T20:14:44.576+0800 [DEBUG] agent.tlsutil: OutgoingRPCWrapper: version=1
    2020-03-18T20:14:44.576+0800 [INFO]  agent.server.raft: initial configuration: index=1 servers="[{Suffrage:Voter ID:58b5abd3-4071-f5d5-bf6d-d87e0e7fb079 Address:127.0.0.1:8300}]"
    2020-03-18T20:14:44.576+0800 [INFO]  agent.server.serf.wan: serf: EventMemberJoin: alias.dc1 127.0.0.1
    2020-03-18T20:14:44.576+0800 [INFO]  agent.server.serf.lan: serf: EventMemberJoin: alias 127.0.0.1
    2020-03-18T20:14:44.577+0800 [INFO]  agent: Started DNS server: address=127.0.0.1:8600 network=udp
    2020-03-18T20:14:44.577+0800 [INFO]  agent.server.raft: entering follower state: follower="Node at 127.0.0.1:8300 [Follower]" leader=
    2020-03-18T20:14:44.579+0800 [INFO]  agent.server: Adding LAN server: server="alias (Addr: tcp/127.0.0.1:8300) (DC: dc1)"
    2020-03-18T20:14:44.579+0800 [INFO]  agent.server: Handled event for server in area: event=member-join server=alias.dc1 area=wan
    2020-03-18T20:14:44.580+0800 [INFO]  agent: Started DNS server: address=127.0.0.1:8600 network=tcp
    2020-03-18T20:14:44.581+0800 [INFO]  agent: Started HTTP server: address=127.0.0.1:8500 network=tcp
    2020-03-18T20:14:44.581+0800 [INFO]  agent: started state syncer
==> Consul agent running!
    2020-03-18T20:14:44.581+0800 [INFO]  agent: Started gRPC server: address=127.0.0.1:8502 network=tcp
    2020-03-18T20:14:44.614+0800 [WARN]  agent.server.raft: heartbeat timeout reached, starting election: last-leader=
    2020-03-18T20:14:44.614+0800 [INFO]  agent.server.raft: entering candidate state: node="Node at 127.0.0.1:8300 [Candidate]" term=2
    2020-03-18T20:14:44.615+0800 [DEBUG] agent.server.raft: votes: needed=1
    2020-03-18T20:14:44.615+0800 [DEBUG] agent.server.raft: vote granted: from=58b5abd3-4071-f5d5-bf6d-d87e0e7fb079 term=2 tally=1
    2020-03-18T20:14:44.615+0800 [INFO]  agent.server.raft: election won: tally=1
    2020-03-18T20:14:44.615+0800 [INFO]  agent.server.raft: entering leader state: leader="Node at 127.0.0.1:8300 [Leader]"
    2020-03-18T20:14:44.615+0800 [INFO]  agent.server: cluster leadership acquired

3.3 Consul注册发现服务

服务发现是基于微服务的体系结构的关键原则之一。尝试手动配置每个客户端或某种形式的约定可能非常困难,也很容易出问题。Consul通过HTTP API和DNS提供服务发现服务。Spring Cloud Consul利用HTTP API进行服务注册和发现。这并不妨碍非spring云应用程序利用DNS接口。Consul代理服务器运行在一个集群中,该集群通过gossip协议进行通信,并使用Raft consensus协议。

我们基于上面的项目进行修改,修改项目的pom文件依赖

<dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-consul-discovery -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        <!--        &lt;!&ndash; https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-zookeeper-discovery &ndash;&gt;-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>-->
<!--        </dependency>-->

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!--        </dependency>-->

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
        <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>
    </dependencies>

application.yml配置文件修改

#eureka注册中心配置
#eureka:
#  client:
#    service-url:
#      defaultZone: http://localhost:8761/eureka/

spring:
  application:
    name: alias-pay
    #zookeeper注册中心配置
#  cloud:
#    zookeeper:
#      connect-string: 122.51.160.240:2181
  cloud:
    consul:
      port: 8500
      host: localhost
      discovery:
        service-name: ${spring.application.name}
        heartbeat:
          enabled: true
        healthCheckPath: ${management.server.servlet.context-path}/health
        healthCheckInterval: 15s
        health-check-critical-timeout: 20s
        enabled: true

项目启动类去掉@EnableEurekaClient注解,使用@EnableDiscoveryClient注解

启动order、pay项目,在浏览器输入localhost:8500,打开consul ui管理控制台。可以看到我们的服务已启动

consul控制台
调用http://localhost:8081/pay/payOrder接口,看到返回支付订单:order服务端口:8083,服务端口:8081说明调用成功。

至于consul的健康检查、键值存储、安全服务通信、多数据中心等功能可参考Consul文档Spring Cloud Consul文档

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章