服务注册中心
概念
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息,比如服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者|服务提供者)以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现RPC本地调用RPC远程服务,
框架核心设计思想
:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)
Eureka
两个组件
集群说明
Eureka搭建(单机版及集群版)
1. Eureka注册中心
- pom.xml
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- yml
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称,本地需要在hosts文件改
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
# 集群指向其它eureka
defaultZone: http://eureka7002.com:7002/eureka/
- 主启动类
@SpringBootApplication
@EnableEurekaServer //作为Eureka服务端
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class,args);
}
}
2. 服务提供者
- pom.xml
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- yml
spring:
application:
name: cloud-payment-service # 该服务的名称,相同的服务名字相同,ip+端口不同
eureka:
client:
# 表示是否将自己注册进EurekaServer 默认为true
register-with-eureka: true
# 是否从eurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url:
# 单机版
# defaultZone: http://localhost:7001/eureka
# 集群版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
- 主启动类
@SpringBootApplication
@EnableEurekaClient //作为Eureka客户端
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}
- controller类
public class PaymentController {
@Resource
private PaymentService paymentService;
//import org.springframework.beans.factory.annotation.Value; 获得配置文件属性
@Value("${server.port}")
private String serverPort;
@ResponseBody
@PostMapping(value = "/payment/create")
public CommonResult create(@RequestBody Payment payment){
int i = paymentService.create(payment);
log.info("****插入结果:"+i);
if(i>0){
return new CommonResult(200,"插入数据成功"+serverPort,i);
}else {
return new CommonResult(444,"插入数据失败",null);
}
}
@RequestMapping(value = "/payment/get/{id}")
@ResponseBody
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id)
{
Payment payment = paymentService.getPaymentById(id);
log.info("数据:{}",payment);
if(payment != null)
{
return new CommonResult(200,"查询成功,serverPort:"+serverPort,payment);
}else{
return new CommonResult(444,"没有对应记录,查询ID: "+id,null);
}
}
}
3. 服务消费者
- pom.xml
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- yml
eureka:
client:
# 表示是否将自己注册进EurekaServer 默认为true
register-with-eureka: true
# 是否从eurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url:
# 单机版
# defaultZone: http://localhost:7001/eureka
# 集群版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
- 主启动类
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}
- 配置RestTemplate
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //赋予负载均衡能力
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
- controller
@RestController
@Slf4j
public class OrderController {
// private static final String PAYMENT_URL = "http://localhost:8001";
private static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE"; //提供者对外开放的服务名
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/create")
public CommonResult create(Payment payment){
return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommonResult getPayment(@PathVariable long id){
return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
}
}
4.附录
- CommonResult
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T> {
//404 Not Found
private Integer code;
private String message;
private T data;
public CommonResult(Integer code, String message) {
this(code,message,null);
}
}
服务发现DisCovery(服务提供者暴露)
- yml
instance:
# 修改status处名称,修改命名规范
instance-id: payment8001
# 访问历经可以显示IP地址
prefer-ip-address: true
- Controller(主要)
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("/payment/discovery")
public Object discovery(){
//获得服务清单,仅名字
List<String> services = discoveryClient.getServices();
for (String elements : services) {
log.info("*********element: +{}",elements);
}
//第二种获得方式,可获得属性
List<ServiceInstance> instances = discoveryClient.getInstances("cloud-payment-service");
for (ServiceInstance instance : instances) {
log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
}
return this.discoveryClient;
}
- 主启动类
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}
Eureka自我保护
- 导致原因
某一时刻某一个微服务不可用了,Eureka不会立刻清除,
依旧会对改为服务的信息进行保存
属于CAP里面的AP分支
- 自我保护模式
- 默认情况下,如果EurekaServer在一定时间内没有收到某个微服务实例的心跳,Eureka将会注销该实例(默认90s)
- 因网络故障可能短时间内丢失很多微服务,
这些微服务本不应该被注销
,此时Eureka开启自我保护模式- 在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例
- Eureka服务端配置
eureka:
server:
#关闭自我保护机制,保证不可用服务被及时踢除
enable-self-preservation: false
# 2ms没有心跳就删除
eviction-interval-timer-in-ms: 2000
- 可在客户端设置心跳发送时间
eureka:
instance:
# Eureka客户端向服务端发送心跳的时间间隔,单位是秒(默认30s)
lease-renewal-interval-in-seconds: 1
# Eureka服务端在收到最后一次心跳后等待时间上限,单位是秒(默认90s)
lease-expiration-duration-in-seconds: 2
Zookeeper
服务提供者配置
- pom.xml (注意这里需要些许操作)
<!-- SpringBoot整合zookeeper客户端 -->
<!-- 注意如果报zookeeper-xxx-beta.jar 错误,就是Jar包不匹配,需以下操作 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--先排除自带的zookeeper3.5.3-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加zookeeper3.4.9版本-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</version>
</dependency>
- yml
#8004表示注册到zookeeper服务器的支付服务提供者端口号
server:
port: 8004
#服务别名----注册zookeeper到注册中心名称
spring:
application:
name: cloud-provider-payment
cloud:
zookeeper:
connect-string: 39.108.176.185:2181
- 主启动类
@SpringBootApplication
@EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务
public class PaymentMain8004 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8004.class,args);
}
}
- controller
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/payment/zk")
public String paymentzk()
{
return "springcloud with zookeeper: "+serverPort+"\t"+ UUID.randomUUID().toString();
}
}
服务消费者配置
- pom同上
- yml
#8004表示注册到zookeeper服务器的支付服务提供者端口号
server:
port: 80
#服务别名----注册zookeeper到注册中心名称
spring:
application:
name: cloud-consumer-order
cloud:
zookeeper:
connect-string: 39.108.176.185:2181
- 主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class OrderZKMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderZKMain80.class,args);
}
}
- 配置类
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced //赋予负载均衡能力
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
- controller
@RestController
@Slf4j
public class OrderZKController {
public static final String INVOKE = "http://cloud-provider-payment";
@Resource
private RestTemplate restTemplate;
@RequestMapping(value = "/consumer/payment/zk",method = RequestMethod.GET)
public String paymentInfo(){
return restTemplate.getForObject(INVOKE + "/payment/zk", String.class);
}
}
基本
- zookeeper创建的是临时节点
- 集群配置同zookeeper
ConSul
基本
- 基本同zookeeper,即服务提供者+消费者
- 访问地址为:host:8500
不确定:consul与客户端之间要相互可以ping通,否则service check不通过,服务无法上线
服务提供者
- pom
<!--SpringCloud consul-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
- yml
server:
port: 8006
spring:
application:
name: consul-provider-payment
cloud:
consul:
host: 192.168.199.132
port: 8500
discovery:
service-name: ${spring.application.name}
prefer-ip-address: true
- 主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8006 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8006.class,args);
}
}
- controller
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/payment/consul")
public String paymentConsul()
{
return "springcloud with consul: "+serverPort+"\t"+ UUID.randomUUID().toString();
}
}
服务消费者
- pom同上
- yml
server:
port: 80
spring:
application:
name: cloud-consumer-order
cloud:
consul:
host: 192.168.199.132
port: 8500
discovery:
service-name: ${spring.application.name}
- 配置类
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced //赋予负载均衡能力
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
- 启动类
@SpringBootApplication
@EnableDiscoveryClient
public class OrderConsulMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderConsulMain80.class,args);
}
}
- controller
@RestController
public class OrderConsulController {
public static final String INVOKE = "http://consul-provider-payment";
@Resource
private RestTemplate restTemplate;
@RequestMapping(value = "/consumer/payment/consul",method = RequestMethod.GET)
public String paymentInfo(){
return restTemplate.getForObject(INVOKE + "/payment/consul", String.class);
}
}
三者异同点
组件名 | 语言 | CAP | 服务健康检查 | 对外暴露接口 | spring Cloud集成 |
---|---|---|---|---|---|
Eureka | Java | AP | 可配支持 | HTTP | 已集成 |
Consul | Go | CP | 支持 | HTTP/DNS | 已集成 |
Zookeeper | Java | CP | 支持 | 客户端 | 已集成 |
CAP
概念
C:Consistency(强一致性,数据一定要一样)
A:Availability(可用性,不宕机)
P:Partition tolerance(分区容错性)
CAP理论关注粒度是数据,而不是整体系统设计的策略
经典CAP图
特点
- 理论核心
最多只能同时较好的满足两个
CAP的理论和形式:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求
- 三大类
- CA:单点集群,
满足一致性,可用性
的系统,通常在可扩展性上不太强大
- CP:满足
一致性,分区容忍性
的系统,通常性能不是特别高
- AP:满足
可用性,分区容忍性
的系统,通常对一致性要求低一些