SpringCloud服务注册中心入门
一、Eureka服务注册功能
1.注册server
1.创建子模块
2.改pom文件
<dependencies>
<!--eureka server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</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>
<!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.xiaoxiao.springcloud</groupId>
<artifactId>cloud-api-common</artifactId>
<version>${project.version}</version>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3.编写YML文件
server:
port: 7001
eureka:
instance:
#eureka服务端的实例名字
hostname: localhost
client:
#表示不向注册中心注册自己
register-with-eureka: false
#表示自己是注册中心,不提供检索功能
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4.编写主方法
5.注解开启Eureka服务
在主方法上注解@EnableEurekaServer
2.编写client
1.改写Pom文件
加入依赖
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.编写yml文件
server:
port: 80
eureka:
client:
#表示向注册中心注册自己
register-with-eureka: true
#表明要从注册中心中抓取自己的信息,集群必须要设置成true才能配合ribbon
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka/
instance:
appname: cloud-order-service
遇到问题
error:Request execution error. endpoint=DefaultEndpoint{ serviceUrl='http://localhost:8761/eureka/}
说明springboot自动调用了默认端口8761作为注册中心,原因肯定是因为yml文件中defaultZone属性赋值失败.我这里是拼写错误
defaultZone: http://localhost:7001/eureka
3.在主方法上进行注解
@EnableEurekaClient
二、Eureka集群原理
一般为了避免单点故障,服务器都是集群式,实现负载均衡+故障容错
1.环境构建
C:\Windows\System32\drivers\etc路径下的hosts文件将127.0.0.1映射集群的名字
2.新建server
和原来的server一样的程序,yaml文件要进行改变
server:
port: 7002
eureka:
instance:
#eureka服务端的实例名字
hostname: eureka7002.com
client:
#表示不向注册中心注册自己
register-with-eureka: false
#表示自己是注册中心,不提供检索功能
fetch-registry: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
3.修改需要注册的服务
只需修改yml文件中的defaultZone,将所有集群的url都写上去
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
4.服务集群
1.新建一个Payment和原来payment功能一样
2.修改消费者的controller
将固定的url转成服务
public final String PAYMENT_URL="http://CLOUD-PAYMENT-SERVICE";
3.在消费者的config加入负载均衡的注解
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
5.actuator微服务信息完善
eureka:
instance:
instance-id: payment8001
prefer-ip-address: true
server:
port: 8001
spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource #当前数据库操作类型
driver-class-name: org.gjt.mm.mysql.Driver #mysql驱动包
#数据库更新后需要加入如下参数,更正编码规则和时区等
url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: root
eureka:
instance:
instance-id: payment8001
prefer-ip-address: true
client:
#表示向注册中心注册自己
register-with-eureka: true
#表明要从注册中心中抓取自己的信息,集群必须要设置成true才能配合ribbon
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
mybatis:
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: com.xiaoxiao.springcloud.entities
6.服务发现Discovery
对于注册到服务中心的微服务,可以通过服务发现来获得该服务的信息
1.在主方法加上@EnableDiscoveryClient
2.在控制层调用
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
@Resource
private DiscoveryClient discoveryClient;
@PostMapping("/payment/create")
public CommonResult<Payment> create(@RequestBody Payment payment) {
int result = paymentService.create(payment);
log.info("插入数据的编号是"+result);
if(result>0) {
return new CommonResult(200,"插入数据成功,serverPort:"+serverPort,result);
}else {
return new CommonResult(444,"插入数据失败,serverPort:"+serverPort,null);
}
}
@GetMapping("/payment/get/{id}")
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+",serverPort:"+serverPort,null);
}
}
@GetMapping("/payment/discovery")
public Object discovery() {
List<String> services = discoveryClient.getServices();
for (String service : services) {
log.info("*****注册的服务有:"+service);
}
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info("*****实例信息有:"+instance+"\t"+instance.getPort()+"\t"+instance.getHost()+"\t"+instance.getInstanceId());
}
return discoveryClient;
}
}
2020-06-22 18:02:21.627 INFO 23416 --- [nio-8001-exec-1] c.x.s.controller.PaymentController : *****注册的服务有:cloud-payment-service
2020-06-22 18:02:21.627 INFO 23416 --- [nio-8001-exec-1] c.x.s.controller.PaymentController : *****注册的服务有:cloud-order-service
2020-06-22 18:02:21.628 INFO 23416 --- [nio-8001-exec-1] c.x.s.controller.PaymentController : *****实例信息有:org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient$EurekaServiceInstance@18435660 8002 192.168.40.1 payment8002
2020-06-22 18:02:21.628 INFO 23416 --- [nio-8001-exec-1] c.x.s.controller.PaymentController : *****实例信息有:org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient$EurekaServiceInstance@669875cd 8001 192.168.40.1 payment8001
7.Eureka的自我保护
自我保护就是在一定时间范围内可能由于断网等意外情况,注册中心收不到服务的心跳回执,也不会将其删除.
#禁止自我保护
server:
enable-self-preservation: false
三、整合zookeeper作为注册中心
这里使用docker运行zookeeper
安装指令是
docker run --name zk01 -p 2181:2181 --restart always -d 镜像id
zookeeper的结点是临时结点,如果短时间内没有心跳回执,就会删除
1.pom文件编写
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</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>
<!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.xiaoxiao.springcloud</groupId>
<artifactId>cloud-api-common</artifactId>
<version>${project.version}</version>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2.编写yml文件
server:
port: 8004
spring:
application:
name: cloud-payment-service
cloud:
zookeeper:
connect-string: 192.168.1.50:2181
3.编写主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8004 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8004.class,args);
}
}
4.编写controller
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/payment/zk")
public String zookeeper() {
return "springcloud with zookeeper" + serverPort + "\t" + UUID.randomUUID().toString();
}
}
5.编写消费者进行调用
@Configuration
public class MyapplicationConfig {
@Bean
@LoadBalanced
public RestTemplate getreRestTemplate() {
return new RestTemplate();
}
}
@RestController
public class PaymentController {
public final String ZKEEPER_URL = "http://cloud-provider-payment";
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/zk")
public String zookeeper() {
String result = restTemplate.getForObject(ZKEEPER_URL + "/payment/zk", String.class);
return result;
}
}
@SpringBootApplication
@EnableDiscoveryClient
public class OrderzkMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderzkMain80.class,args);
}
}
server:
port: 80
spring:
application:
name: cloud-consumer-orderzk80
cloud:
zookeeper:
connect-string: 192.168.1.50:2181
要注意细节,一定要注意!
四、Consul作为服务注册中心
1.运行consul
在下载目录下cmd执行consul agent -dev启动
2.新建子模块
3.改写pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
4.编写yml
server:
port: 8006
spring:
application:
name: consul-provider-payment
cloud:
consul:
discovery:
service-name: ${spring.application.name}
port: 8500
host: localhost
5.编写主方法
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentConsulMain8006 {
public static void main(String[] args) {
SpringApplication.run(PaymentConsulMain8006.class,args);
}
}
6.编写controller
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/payment/consul")
public String zookeeper() {
return "com.xiaoxiao.springcloud with consul" + serverPort + "\t" + UUID.randomUUID().toString();
}
}
7.注册消费者
和前面的方法一样,注意修改yml中的服务名即可…
五、注册中心内容总结
1.三种注册中心异同点
如CAP经典理论图所示
CAP的核心理论是:一个分布式系统不可能同时很好的满足一致性,可用和分区容错性三个需求。其中C为Consistency(强一致性),A为Availability (可用性),P为Partitiontolerance(分区容错性),CAP 理论关注细粒度是数据,而不是整体系统设计的。根据需求,只能满足其中两个。
CA - 单点集群,满足一致性,可用性的系统,通常拓展性不是特别强大。
CP - 满足一致性,分区容错性的系统,通常性能不是特别高
AP - 满足可用性,分区容错性的系统,通常对一致性的要求要低一些。
在上面学习的三种组件功能如下:
组件名 | 语言 | CAP | 服务健康检查 | 对外暴露接口 | Spring Cloud集成 |
---|---|---|---|---|---|
Eureka | Java | AP | 可配支持健康检查 | HTTP | 集成 |
Consul | GO | CP | 支持健康检查 | HTTP、DNS | 集成 |
Zookeeper | Java | CP | 支持健康检查 | 客户端 | 集成 |
2.总结与收获
今天学习了一天的服务注册中心相关知识,并实现了一遍,但实现过程中有大大小小的错误,都造成了极大的困扰,结果最后一看,不是字母写错了,就是忘了加配置,以后一定要细心细心再细心,加油!