微服务基本组成
Eureka
- 服务治理:管理服务与服务之间的依赖关系,可以实现服务调用、负载均衡、容错等,实现服务注册与发现
- 服务注册与发现:Eureka采用了CS的设计架构,EurekaServer作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用心跳连接,通过监控EurekaServer就可以监控各个微服务是否正常
EurekaServer
- 提供服务注册服务
- 各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样在服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到
EurekaClient
- 通过注册中心进行访问
- 是一个Java客户端,用于简化EurekaServer的交互,客户端同时也具备一个内置的,使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向EurekaServer发生心跳(默认周期为30秒)
- 如果EurekaServer在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除
单机版Eureka构建
server端
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| server: port: 7001 eureka: instance: hostname: localhost client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
|
1 2 3 4 5 6 7
| @SpringBootApplication @EnableEurekaServer public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class,args); } }
|
client端
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| server: port: 8001 spring: application: name: cloud-payment-service eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:7001/eureka
|
1 2 3 4 5 6 7
| @SpringBootApplication @EnableEurekaClient public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); } }
|
consumer
1 2 3 4 5 6 7
| @Configuration public class ApplicationContextConfig { @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @RestController @RequestMapping("/consumer/payment") @Slf4j public class OrderController { public static final String PAYMENT_URL = "http://localhost:8001";
@Autowired private RestTemplate restTemplate;
@GetMapping("/create") public CommonResult<Payment> create(Payment payment) { return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class); }
@GetMapping("/select/{id}") public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) { return restTemplate.getForObject(PAYMENT_URL + "/payment/select/" + id, CommonResult.class); } }
|
集群版Eureka构建
server端
只需要修改yml配置文件即可
1 2 3 4 5 6 7 8 9 10 11 12
| server: port: 7001 eureka: instance: hostname: eureka7001.com client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://eureka7002.com:7002/eureka/
|
1 2 3 4 5 6 7 8 9 10 11 12
| server: port: 7002 eureka: instance: hostname: eureka7002.com client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://eureka7001.com:7001/eureka/
|
client端
注册多个server端
1 2 3 4 5 6 7 8 9 10 11 12
| server: port: 8001 spring: application: name: cloud-payment-service eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
|
consumer
1 2 3 4 5 6 7 8
| @Configuration public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @RestController @RequestMapping("/consumer/payment") @Slf4j public class OrderController { public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE"; @Autowired private RestTemplate restTemplate;
@GetMapping("/create") public CommonResult<Payment> create(Payment payment) { return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class); }
@GetMapping("/select/{id}") public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) { return restTemplate.getForObject(PAYMENT_URL + "/payment/select/" + id, CommonResult.class); } }
|
服务名称和ip显示
在client端配置
1 2 3 4 5 6
| eureka: instance: instance-id: payment8001 prefer-ip-address: true
|
Discovery
对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息
1 2 3 4 5 6 7 8 9
| @SpringBootApplication @EnableEurekaClient
@EnableDiscoveryClient public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import org.springframework.cloud.client.discovery.DiscoveryClient;
@Resource private DiscoveryClient discoveryClient;
@GetMapping("/discovery") public Object discovery(){ List<String> services = discoveryClient.getServices(); for (String element : services) { log.info("***** element:"+element); } 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 discoveryClient; }
|
Eureka自我保护
- 某时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存
- 属于CAP里面的AP分支
关闭自我保护
1 2 3 4 5 6
| eureka: server: enable-self-preservation: false eviction-interval-timer-in-ms: 2000
|
1 2 3 4 5 6
| eureka: instance: lease-expiration-duration-in-seconds: 2 lease-renewal-interval-in-seconds: 1
|
Zookeeper
引入依赖
1 2 3 4 5 6 7 8
|
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> </dependency>
|
配置yml
1 2 3 4 5 6 7
| spring: application: name: cloud-provider-payment cloud: zookeeper: connect-string: 192.168.0.13:2181
|
编写启动类
1 2 3 4 5 6 7 8
| @SpringBootApplication
@EnableDiscoveryClient public class PaymentMain8004 { public static void main(String[] args) { SpringApplication.run(PaymentMain8004.class, args); } }
|
Consul
docker安装
1 2 3 4 5 6 7 8 9 10
| # 下载 docker pull consul # 创建指定文件夹 mkdir -p /data/consul/{conf,data} # 创建容器 docker run --name consul -p 8500:8500 -v /data/consul/conf/:/consul/conf/ -v /data/consul/data/:/consul/data/ -d consul # 启动 docker start consul # 访问 http://192.168.0.13:8500
|
引入依赖
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency>
|
配置yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| server: port: 8006
spring: application: name: consul-provider-payment cloud: consul: host: 192.168.0.13 port: 8500 discovery: service-name: ${spring.application.name} health-check-url: http://192.168.0.14:8006/actuator/health hostname: 192.168.0.14
|
编写启动类
1 2 3 4 5 6 7
| @SpringBootApplication @EnableDiscoveryClient public class PaymentConsul8006 { public static void main(String[] args) { SpringApplication.run(PaymentConsul8006.class,args); } }
|
异同点
- CAP:C:Consistency(强一致性),A:Availability(可用性),P:Partition tolerance(分区容错)
- CAP理论关注粒度是数据,而不是整体系统设计的策略
组件 |
语言 |
CAP |
服务健康检查 |
对外暴露接口 |
SpringCloud集成 |
Eureka |
JAVA |
AP |
可配支持 |
HTTP |
已集成 |
Consul |
GO |
CP |
支持 |
HTTP/DNS |
已集成 |
Zookeeper |
JAVA |
CP |
支持 |
客户端 |
已集成 |
AP架构
- 当网络分区出现后,为了保证可用性,系统B可以返回旧值,保证系统可用性
- 结论:违背了一致性C的要求,只满足可用性和分区容错,即AP
CP架构
- 当网络分区出现后,为了保证一致性,就必须拒绝连接请求
- 结论:违背了可用性A的要求,只满足一致性和分区容错,即CP
相关文章
SpringCloud
服务降级
服务调用
服务网关
服务配置和服务总线
Stream消息驱动
SpringCloud-OpenFeign问题
SpringCloud-GateWay工具类
DockerCompose常用软件配置
SpringQuartz动态定时任务