注册中心
1.什么是注册中心?
注册中心,主要包括3个组件要素,第一个就是注册中心,第二个就是消费者,第三个就是生产者.
注册中心
注册中心就是类似于淘宝商城,他的作用有两个.
- 1.消费者要消费,调用接口,他告诉消费者,调用的服务的ip地址和端口是哪个.
- 2.为了保证消费者每次访问的接口都正确,不是过期的地址,虽然消费者和生产者注册上来,但中途由于服务器宕机,关机等,他需要保证提供的服务对应的ip地址的实时性.
由于以上原因,注册中心必须保证服务与ip地址的实时对应关系,这就涉及到了一致性协议.CAP理论.
消费者:
消费者就是我们需要调用其他的微服务模块的接口,获取数据.但是一个微服务可能既是消费者,也是生产者,就像淘宝用户,既可以是卖家,也可以是买家.
生产者:
微服务的提供者,也就是提供接口,给其他微服务模块调用.同时一个生产者也可以是一个消费者.
2.解释CAP理论
CAP理论指的是一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。拿一个网上的图来看看。
Consistency 一致性
一致性指的是所有节点在同一时间的数据完全一致。就好比刚刚举得例子中,小明和小华读取的都是正确的数据,对他们用户来说,就好像是操作了同一个数据库的同一个数据一样。
因此对于一致性,也可以分为从客户端和服务端两个不同的视角来理解。
(1)客户端
从客户端来看,一致性主要指的是多并发访问时更新过的数据如何获取的问题。也就是小明和小华同时访问,如何获取更新的最新的数据。
(2)服务端
从服务端来看,则是更新如何分布到整个系统,以保证数据最终一致。也就是N1节点和N2节点如何通信保持数据的一致。
一致性分类
对于一致性,一致的程度不同大体可以分为强、弱、最终一致性三类。
-
强一致性
对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。 -
弱一致性
如果能容忍后续的部分或者全部访问不到,则是弱一致性。 -
最终一致性
如果经过一段时间后要求能访问到更新后的数据,则是最终一致性。
可用性(Availability)
可用性指服务一直可用,而且是正常响应时间。就好比刚刚的N1和N2节点,不管什么时候访问,都可以正常的获取数据值。而不会出现问题。好的可用性主要是指系统能够很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。
对于可用性来说就比较好理解了。
分区容错性(Partition tolerance)
分区容错性指在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。就好比是N1节点和N2节点出现故障,但是依然可以很好地对外提供服务。
这个分区容错性也是很好理解。
3.为什么需要注册中心?
- 一个个的微服务模块之间调用,以前使用的ip地址调用,如果服务宕机,则我们不能及时获知,代码就会报错.
- 就算我们可以在调用之前,先测试以下对方的测试端口,但是这会导致我们的编码难度增高
- 如果我们调用的服务是集群的,有多个服务,我们还需要自己书写负载均衡的算法.
4.注册中心对比
现在市面上的注册中心对比
4.1 架构及性能对比图
4.2 使用对比
Eureka | Zookeeper | Consul | Nacos | |
---|---|---|---|---|
server搭建 | 引入server的依赖,在代码中搭建一个server项目 | 安装包 | 安装包 | 安装包 |
pom | spring-cloud-starter-netflix-eureka-client | spring-cloud-starter-zookeeper-discovery | spring-cloud-starter-consul-discovery | 1.cloud-alibaba管理依赖版本 2.spring-cloud-starter-alibaba-nacos-discovery |
yml | 配置连接 | 配置连接 | 配置连接 | 配置连接 |
启动注解 | @EnableEurekaClient | @EnableDiscoveryClient | @EnableDiscoveryClient | @EnableDiscoveryClient |
(1) server端搭建
- Eureka是引入Eureka-server的依赖,在项目中搭建一个server端服务项目.具体怎么搭建,请看下面的Eureka详解.
- zookeeper是下载安装包,安装server端
- consul也是下载安装包,安装server端
- nacos也是下载安装包,安装server端.
(2) 客户端 pom依赖
- Eureka是引入eureka-client客户端依赖,并且父级版本管理是spring-cloud-dependencies;
<!-- Eureka 的client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- zookeeper是引入zookeeper的启动依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
- consul是引入consul的启动依赖
<!-- consul的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
- nacos是引入nacos的启动依赖
父项目中需引入cloud-alibaba来管理依赖
<!--spring cloud alibaba 2.1.0.RELEASE-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
子module项目需引入nacos的依赖
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
(3) yml配置
- eureka
eureka:
client:
register-with-eureka: true #向服务中心注册
fetchRegistry: true #向服务中心拉取注册信息
service-url: #Eureka的地址
#单机版
defaultZone: http://eureka7001.com:7001/eureka
#集群版
#defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
- zookeeper
spring:
application:
name: cloud-consumer-order
cloud:
zookeeper: #zookeeper的连接配置
connect-string: 118.190.58.27:2181,118.190.58.27:2182,118.190.58.27:2183
- consul
spring:
application:
name: consul-consumer-order
cloud:
consul: #consul的连接配置
host: localhost #主机
port: 8500 #端口
discovery:
service-name: ${spring.application.name}
- nacos
spring:
application:
name: nacos-order-consumer
cloud:
nacos: #nacos的配置
discovery:
server-addr: localhost:8848
(4) 启动注解
- eureka使用的是@EnableEurekaClient
- zookeeper/consul/nacos使用的是@EnableDiscoveryClient
Eureka
Eureka分为两大组件,第一个是Eureka服务端,一个是Eureka客户端,其实所有的注册中心,也不止注册中心,是很多组件都是这样的设计模式,包括MQ也是.都是服务端和客户端,其实就是平台模式.
区别就是,注册中心类似于淘宝,我只是提供一个平台,你买东西还是得联系具体的卖家.而消息中间价MQ就类似于,你把东西卖给我,你就不用管了,我再去卖给其他人,这就是中间商,但是模式都是客户端,服务端模式.
一.搭建Eureka的服务端
单机版
1.建module
略
2.改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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--继承父项目-->
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<!--Eureka的server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--公共的modul-->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- web -->
<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>
<!-- 热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- springboot的测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
3.写yml
server: #server的端口
port: 7001
eureka:
instance: #这是陪着Eureka注册到server上的显示相关信息
hostname: eureka7001.com #eureka服务端显示的实例名字
client: #这是配置客户端连接到Server的连接相关的信息
register-with-eureka: false #表识不向注册中心注册自己
fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
service-url:
#单机版 设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://localhost:${server.port}/eureka/
#集群版,注册到7002
#defaultZone: http://eureka7002.com:7002/eureka/
server: # 这是配置Eureka Server服务相关的信息
enable-self-preservation: false # 关闭自我保护
eviction-interval-timer-in-ms: 2000
4.主启动
@EnableEurekaServer 启动EurekaServer的注解
//启动Eureka服务
@EnableEurekaServer
@SpringBootApplication
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class,args);
}
}
5.测试
http://localhost:7001/
集群版
集群版就是在复制一个上面的项目,端口号修改一下,在yml注册的时候,相互注册就好了.
二.搭建Eureka的客户端
1.建module
略
2.改pom
<!--添加eureka-client的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3.写yml
eureka:
client:
register-with-eureka: true #向服务中心注册
fetchRegistry: true #向服务中心拉取注册信息
service-url: #Eureka的地址
#单机版
defaultZone: http://eureka7001.com:7001/eureka
#集群版 一定不能多了上面的最后的
#defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
# 微服务服务实例id的修改,
instance:
#实例id
instance-id: payment8001
#ip地址的显示
prefer-ip-address: true
#Eureka客户端向服务端发送心跳间隔时间
lease-renewal-interval-in-seconds: 1
#Eureka服务端再收到最后一次心跳等待时间上线,超时将剔除
lease-expiration-duration-in-seconds: 2
4.主启动
@EnableFeignClients //启动openFeign
@SpringBootApplication
@EnableFeignClients //启动openFeign
public class OrderFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignMain80.class,args);
}
}
5.业务代码
5.1 向spring容器中注入RestTemplate对象
@Configuration
public class ApplicationContextConfig {
/**
* 注入一个rest风格调用主体类
* @return
*/
@Bean
//负载均衡策略,使用集群策略,如果调用的服务,有多个服务提供者,则这个注解不能少,少了就会报错(因为计算机不知道调用哪个具体的服务实例)
//这是ribbon的负责均衡注解,因为eureka已经集成了ribbon,所以就可以直接用此注解
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
5.2 业务代码发起远程调用
@RestController
@Slf4j
public class OrderController {
//public static final String PAYMENT_URL = "http://localhost:8001"; 单机版,写死
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE"; //集群版,根据服务名来选择提供服务的服务
@Autowired
private RestTemplate template;
@GetMapping("/consumer/payment/{id}")
public CommonResult findPaymentById(@PathVariable("id") Long id){
CommonResult result = template.getForObject(PAYMENT_URL + "/payment/" + id, CommonResult.class);
return result;
}
@PostMapping("/consumer/payment")
public CommonResult create(Payment payment){
CommonResult result = template.postForObject(PAYMENT_URL + "/payment", payment, CommonResult.class);
return result;
}
//利用restTemplate获取更详细的结果,包括状态码等信息
@GetMapping("/consumer/payment/getForEntity/{id}")
public CommonResult findPaymentById2(@PathVariable("id") Long id){
ResponseEntity<CommonResult> entity = template.getForEntity(PAYMENT_URL + "/payment/" + id, CommonResult.class);
log.info(entity.getStatusCode().getReasonPhrase());
if(entity.getStatusCode().is2xxSuccessful()){
//返回相应状态码为2xx,表示成功
return entity.getBody();
}else {
return new CommonResult(444,"没有查询到该id的记录,该id为:" + id);
}
}
}
以上就是Eureka的使用.