服务注册中心

Eureka

什么是服务治理?
springcloud封装了Netflix公司开发的Eureka模块来实现服务治理

在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂。所有要使用夫妇治理,管理服务与服务之间的依赖关系,可以实现服务调用,负载均衡,容错等。实现服务发现和注册。

单机Eureka搭建步骤

  1. 构建服务端

    修改pom文件:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <dependencies>
    <!-- 自定义api通用包-->
    <dependency>
    <groupId>top.zfxt.springcloud</groupId>
    <artifactId>cloud-api-commons</artifactId>
    <version>1.0-SNAPSHOT</version>
    </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>
    <!-- eureka服务端-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-reflect -->
    <dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-reflect</artifactId>
    <version>1.9.0</version>
    <scope>runtime</scope>
    </dependency>


    </dependencies>
    修改yml文件:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    server:
    port: 7001

    eureka:
    instance:
    hostname: localhsot #eureka服务端的实例名称
    client:
    #false 表示不会注册自己
    register-with-eureka: false
    # false表示自己就是注册中心,职责是维护服务实例。不需要检索服务
    fetch-registry: false
    service-url:
    defaultZone: http://${eureka.instance.hostnmae}:${server.port}/eureka/

主启动文件:

1
2
3
4
5
6
7
@SpringBootApplication
@EnableEurekaServer
open class EurekaMain7001
fun main(args: Array<String>) {
runApplication<EurekaMain7001>(*args)
}
//添加注解设置为服务端

注册其他服务到eureka中

  1. 导包:
    1
    2
    3
    4
    5
    <!--        eureka客户端-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
  2. 添加yml

    这里要注意一个内容:

    1
    2
    3
    4
    spring:
    application:
    name: cloud-payment-name
    # 这里配置的服务名字影响到了后期如何快捷的调用服务和负载均衡
1
2
3
4
5
6
7
8
eureka:
client:
#true 表示注册自己,默认为true
register-with-eureka: true
# 是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须使用true,并配合ribbon使用负载均衡
fetch-registry: false
service-url:
defaultZone: http://localhost:7001/eureka
  1. 主启动添加注解:
    @EnableEurekaClient

Eureka集群

情景:

实现负载均衡+故障容错
集群注册原理:互相注册,相互守望

搭建
新建module,改pom都没有问题。
但是如果需要配置集群的话,需要为两个服务器配置不同的地址和名称,并且相互注册。如下:
(前提是你再hosts文件里配置好了eureka7001.com和eureka7002.com的地址都指向了127.0.0.1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 7001
server:
port: 7001

eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
#false 表示不会注册自己
register-with-eureka: false
# false表示自己就是注册中心,职责是维护服务实例。不需要检索服务
fetch-registry: false
service-url:
defaultZone: http://eureka7002.com:7002/eureka
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 7002
server:
port: 7002

eureka:
instance:
hostname: eureka7002.com #eureka服务端的实例名称
client:
#false 表示不会注册自己
register-with-eureka: false
# false表示自己就是注册中心,职责是维护服务实例。不需要检索服务
fetch-registry: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka

然后为其他微服务配置进入这个eureka集群中
他与原来的区别只有:

1
2
#      defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版

仅此而已

kotlin在springboot中的使用
需要注意的是,kotlin自身的string字符串中默认就有$内插字符串。所以在使用springboot中的$符号时,需要加上\转义符。例如:
文中的@Value(“${server.port}”)是需要添加转义符才能添加进去的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@RestController
class PaymentController {
private val log = LoggerFactory.getLogger(javaClass)
@Value("\${server.port}")
private lateinit var serverPort:String
@Autowired
private lateinit var paymentService: PaymentService

@PostMapping("/payment/create")
fun create(@RequestBody payment: Payment): CommonResult<out Int> {
log.info("*****插入数据:$payment")
val result = paymentService.create(payment)
log.info("*****插入结果:$result")

if (result > 0) {
return CommonResult(200, "插入数据成功,服务端口:$serverPort", result)
} else {
return CommonResult(444, "插入数据失败", null)
}
}

@GetMapping("/payment/get/{id}")
fun getPaymentById(@PathVariable("id") id: Long): CommonResult<*> {
val result = paymentService.getPaymentById(id)
log.info("*****查询结果:$result")
return CommonResult(200, "查询数据成功,服务端口:$serverPort", result)
}
}

负载均衡

  1. 修改服务的调用方式,从固定改为从eureka获取:
1
2
3
//    private val PAYMENT_URL = "http://localhost:8001"

private val PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE"

如上
2.

添加注解

1
2
3
4
5
@Bean
@LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
open fun restTemplate() = RestTemplate().apply {
messageConverters.add(0,gsonHttpMessageConverter)
}

actuator微服务信息完善

  1. 修改主机名称。(让他只暴露服务名称)
    在eureka中加上instance实例id
  2. 访问信息有IP地址

服务发现Discovery

他可以访问到所有微服务的类型和信息

  1. 配置@EnableDiscoveryClient注解在主启动类上
1
2
@EnableDiscoveryClient
open class PaymentMain8001
  1. controller中添加一个client自动注入discoveryClient

    1
    2
    @Resource
    private lateinit var discoveryClient: DiscoveryClient
  2. 配置一个get服务测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @GetMapping("/payment/discovery")
    fun discovery():DiscoveryClient{
    val services = discoveryClient.services
    services.forEach {
    log.info("*****element:$it")
    }
    val instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE")
    instances.forEach {
    log.info("*****instance:${it.uri}")

    }
    return discoveryClient
    }


    可以获取所有的微服务信息

Eureka自我保护机制



服务端:

客户端:

Zookeeper

  1. 搭建注册中心

    可以简单的使用docker来搭建,或者直接用服务器
    这里演示docker

    1
    2
    3
    4
    # 拉取ZooKeeper镜像最新版本
    docker pull zookeeper:latest
    # 启动docker
    docker run -d -e TZ="Asia/Shanghai" -p 2181:2181 --name zookeeper --restart always zookeeper

    更多关于zookeeper的内容可以查看该文章

  2. 建module

  3. 改pom
    去除掉eureka的包,导入zookeeper包

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    </dependency>
  4. 改yam

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    server:
    port: 8004

    # 服务别名,注册zookeeper到注册中心名称
    spring:
    application:
    name: cloud-provider-payment
    cloud:
    zookeeper:
    connect-string: localhost:2181
  5. 然后添加discoveryClient用来获取微服务信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
{
"discoveryClients": [
{
"serviceDiscovery": {},
"zookeeperDiscoveryProperties": {
"hostInfo": {
"override": false,
"ipAddress": "192.168.200.1",
"hostname": "localhost"
},
"enabled": true,
"root": "/services",
"uriSpec": "{scheme}://{address}:{port}",
"instanceHost": "localhost",
"instanceIpAddress": "192.168.200.1",
"preferIpAddress": false,
"register": true,
"metadata": {},
"initialStatus": "UP",
"order": 0
}
},
{
"simpleDiscoveryProperties": {
"instances": {},
"local": {
"uri": "http://localhost:8004",
"host": "localhost",
"port": 8004,
"secure": false,
"metadata": {},
"serviceId": "cloud-provider-payment"
},
"order": 0
}
}
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
@GetMapping("/payment/zk")
fun discovery(): Any {
val services = discoveryClient.services
services.forEach {
log.info("*****element:$it")
}
val instances = discoveryClient.getInstances("cloud-provider-payment")
instances.forEach {
log.info("*****instance:${it.uri}")

}
return discoveryClient
}

访问方法如上
结果:

zookeeper没有自动保护机制,节点退出后立刻就会消失

至于zookeeper的使用。与eureka类似。只要不写死调用端口,而使用服务名。即private val url = "http://cloud-provider-payment"一样可以实现负载均衡

Consul


不做具体配置。知道有这个东西即可。需要使用时,可以很容易的从以上两点得到启发。

三者异同