一、服务发现(Eureka/Consul/ZooKeeper)
1、Eureka介绍
Netflix Eureka是Spring Cloud服务注册发现的基础组件
Eureka提供RESTful风格(HTTP协议)的服务注册与发现
Eureka采用C/S架构,Spring Cloud内置客户端
2、Eureka的组成
Eureka的组成
3、搭建Eureka注册中心
启动Idea -> Spring Initializr 向导 组件向导选中 Spring Cloud Discovery -> Eureka Server SpringBoot版本选择 2.1.8 Spring Boot 2.1.8 对应了Spring Cloud Greewich SR3 pom.xml确保引入 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> 下载慢可以引入阿里云镜像仓库 <repositories> <repository> <id>aliyun</id> <name>aliyun</name> <url>https://maven.aliyun.com/repository/public</url> </repository> </repositories> application.yml server: port: 8761 #端口 eureka: server: enable-self-preservation: false #关闭自我保护 instance: #设置注册中心应用名 appname: provider-service#名称 hostname: localhost#正式环境写域名 client: service-url: defaultZone: http://localhost:8761/eureka/ #设置默认区域注册中心 register-with-eureka: false #禁止自注册 fetch-registry: false #是否注册中心获取其他微服务的注册信息 EurekaServerApplication 增加@EnableEurekaServer注解启用Eureka服务器 @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
启用应用,访问 http://localhost:8761
eurekaServer界面
4、开发Eureka客户端(微服务)
Eureka组成
Eureka客户端开发要点
maven依赖spring-cloud-starter-netflix-eureka-client application.yml
配置eureka.client.service-url.defaultZone
入口类增加@EnableEurekaClient
创建新工程eureka-client 启动Spring-Initialzr向导 , 选择 Web -> Spring Web Spring Cloud Discovery -> Eureka Discovery Client 确认Spring Boot 版本为2.1.8 pom.xml确保 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> application.yml server: port: 80 #端口 spring: application: name: order-service #微服务名称 必须全局唯一 eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ #注册中心地址 入口类增加@EnableEurekaClient,启用Eureka客户端 @SpringBootApplication @EnableEurekaClient public class EurekaClientApplication { public static void main(String[] args) { SpringApplication.run(EurekaClientApplication.class, args); } }
先启动注册中心,在启动客户端,访问 localhost:8761查看eureka注册中心,看到客户端注册
image.png
5、Eureka名词概念与自我保护
Eureka名词概念
Register - 服务注册, 向Eureka进行注册登记
Renew - 服务续约,30秒/次心跳包健康检查.90秒未收到剔除服务
Fetch Registries - 获取服务注册列表,获取其他微服务地址
Cancel - 服务下线, 某个微服务通知注册中心暂停服务
Eviction - 服务剔除,90秒未续约,从服务注册表进行剔除
Eureka自我保护机制
Eureka在运行期去统计心跳失败率在15分钟之内是否低于 85%
如果低于 85%,会将这些实例保护起来,让这些实例不会被剔除
关闭自我保护:eureka.服务实例.
enable-self-preservation: false
PS: 如非网络特别不稳定,建议关闭
6、Eureka高可用配置
Eureka高可用配置
Eureka高可用配置步骤
服务提供者defaultZone指向其他的Eureka
客户端添加所有Eureka 服务实例 URL
Eureka只能绑定域名,在本地测试需要修改DNS配置文件hosts 编辑 c:/windows/system32/drivers/etc/hosts # localhost name resolution is handled within DNS itself. # 127.0.0.1 localhost # ::1 localhost 127.0.0.1 server1 127.0.0.1 server2 127.0.0.1 server3 高可用配置: application-p8761.yml 启动项 Program arguments:--spring.profiles.active=8761 server: port: 8761 eureka: instance: appname: provider-service hostname: server1 #必须是域名 client: service-url: defaultZone: http://server2:8762/eureka/,http://server3:8763/eureka/ #向其他注册中心节点注册 application-p8762.yml 启动项 Program arguments:--spring.profiles.active=8762 server: port: 8762 eureka: instance: appname: provider-service hostname: server2 client: service-url: defaultZone: http://server1:8761/eureka/,http://server3:8763/eureka/ #向其他注册中心节点注册 application-p8763.yml 启动项 Program arguments:--spring.profiles.active=8763 server: port: 8763 eureka: instance: appname: provider-service hostname: server3 client: service-url: defaultZone: http://server1:8761/eureka/,http://server2:8762/eureka/ #向其他注册中心节点注册 入口类增加@EnableEurekaServer @SpringBootApplication @EnableEurekaServer public class HaEurekaServerApplication { public static void main(String[] args) { SpringApplication.run(HaEurekaServerApplication.class, args); } } 客户端指向所有Eureka注册中心节点 server: port: 80 spring: application: name: order-service eureka: client: service-url: defaultZone: http://server1:8761/eureka/,http://server1:8762/eureka/,http://server1:8763/eureka/
7、Actuator监控组件
Actuator自动为微服务创建一系列的用于监控的端点
Actuator在SpringBoot自带,SpringCloud进行扩展
pom.xml依赖spring-boot-starter-actuator
Actuator监控端点
二、服务间通信
1、微服务之间调用的两种方式
RestTemplate + @LoadBalanced 显式调用
OpenFeign 隐藏微服务间通信细节
2、Ribbon客户端负载均衡
1.Ribbon是Netfilix开源的客户端负载均衡组件
Ribbon是RestTemplate与OpenFeign的通信基础
Ribbon执行过程
2.Ribbon负载均衡策略
Ribbon七种负载均衡模式
##在消费者中进行设置 application.yml 针对某一个微服务设置负载均衡 book-service: #微服务id ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #随机策略 全局设置,全局设置优先级高于application.yml设置 @SpringBootApplication @EnableEurekaClient public class MemberServiceApplication { @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } @Bean //全局负载均衡策略 public IRule ribbonRule(){ return new RoundRobinRule(); } public static void main(String[] args) { SpringApplication.run(MemberServiceApplication.class, args); } }
3、RestTemplate + @LoadBalanced 显式调用代码实现
1.搭建eureka注册中心
2.搭建客户端服务
图书服务 Spring Initializr Web->Eureka Discovery Client application.yml spring: application: name: book-service eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ BookController @GetMapping("/bsn") public Book findBySN(String sn, HttpServletRequest request){ /*try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); }*/ Book book = null; if(sn.equals("1111")){ book = new Book("1111", "测试图书1", String.valueOf(request.getLocalPort())); }else if(sn.equals("2222")){ book = new Book("2222", "测试图书2", String.valueOf(request.getLocalPort())); }else if(sn.equals("3333")){ book = new Book("3333", "测试图书3", String.valueOf(request.getLocalPort())); } return book; } 启动两个服务,复制两个启动项,修改启动端口 Program arguments: --server.port=8000 Program arguments: --server.port=8001 ![image.png](https://upload-images.jianshu.io/upload_images/15616626-85a94565554a22ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
3.搭建消费端服务
RestTemplate介绍 RestTemplate是Spring Cloud访问Restful API的请求对象 RestTemplate与HttpClient、OKHttp职能类似 @LoadBalanced注解 @LoadBalanced是Ribbon提供的客户端负载均衡注解 通常RestTemplate与@LoadBalanced联合使用 创建订单服务 Spring Initializr web->Spring Web Spring Cloud Discovery -> Eureka Discover Client Spring Cloud Routing -> Ribbon 确保pom.xml引入ribbon <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> appliaction.yml spring: application: name: member-service eureka: client: service-url: defaultZone: http://localhost:8761/eureka 入口类注入RestTemplate @SpringBootApplication @EnableEurekaClient public class MemberServiceApplication { @Bean //注入 @LoadBalanced //Ribbon负载均衡,默认轮询 public RestTemplate restTemplate(){ return new RestTemplate(); } } 业务开发,服务间通信 @Controller public class MemberController { @Resource private RestTemplate restTemplate; @GetMapping("/borrow") @ResponseBody public String borrow(String sn){ /* RestTemplate负载均衡格式要求: http://微服务id/webapi地址 */ Book book = restTemplate.getForObject("http://book-service/bsn?sn=" + sn, Book.class);#传入参数为返回值的实体类 return book.getName() + ":" + book.getDesc() + "图书借阅成功"; } } 业务实体Book与JSON属性对应即可 public class Book { private String sn; private String name; private String desc; public String getSn() { return sn; } public void setSn(String sn) { this.sn = sn; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } }
4、OpenFeign服务间通信
1.Feign与OpenFeign
Feign是一个开源声明式WebService客户端,用于简化服务通信
Feign采用“接口+注解”方式开发,屏蔽了网络通信的细节
OpenFeign是SpringCloud对Feign的增强,支持Spring MVC注解
2.使用openFeign进行服务间调用
1.新建Spring boot Web项目,application name 为 product-service
在pom.xml中引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
spring-cloud-starter-alibaba-nacos-discovery作用为向Nacos server注册服务。
spring-cloud-starter-openfeign作用为实现服务调用。
2.修改application.yml配置文件
spring: cloud: nacos: discovery: server-addr: localhost:8848 application: name: product-service server: port: 8083
3.在启动类上添加@EnableDiscoveryClient、@EnableFeignClients注解
package com.example.productservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class ProductServiceApplication { public static void main(String[] args) { SpringApplication.run(ProductServiceApplication.class, args); } }
4.编写OrderClient Interface
注:/api/v1/order/test 会在下面order-service声明。
OrderClient.java
package com.example.productservice.client; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Component @FeignClient("order-service") public interface OrderClient { @RequestMapping(method = RequestMethod.GET, value = "/api/v1/order/test") String callOrder(); }
5.编写Controller和service
ProductController.java
package com.example.productservice.controller; import com.example.productservice.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController public class ProductController { @Autowired ProductService productService; @RequestMapping(value = "testCallOrder", method = RequestMethod.GET) public String testCallOrder() { return productService.callOrder(); } }
ProductService.java
package com.example.productservice.service; import com.example.productservice.client.OrderClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class ProductService { @Autowired OrderClient orderClient; public String callOrder() { String response = orderClient.callOrder(); return response; } }
3、OpenFeign工作原理
image.png
4、OpenFeign负载均衡策略
OpenFeign负载均衡策略
5、OpenFeign通信日志
1.OpenFeign开启通信日志
基于SpringBoot的logback输出,默认debug级别
设置项:feign.client.config.微服务id.loggerLevel
微服务id:default代表全局默认配置
2.通信日志输出格式
NONE: 不输出任何通信日志
BASIC: 只包含URL、请求方法、状态码、执行时间
HEADERS:在BASIC基础上,额外包含请求与响应头
FULL:包含请求与响应内容最完整的信息
3.OpenFeign日志配置项
LoggerLevel开启通信日志
ConnectionTimeout与ReadTimeout
利用httpclient或okhttp发送请求
6、替换OpenFeign通信组件
1.OpenFeign通信组件
OpenFeign基于JDK原生URLConnection提供Http通信
OpenFeign支持Apache HttpClient与Square OkHttp
SpringCloud按条件自动加载应用通信组件
2.应用条件
Maven引入feign-okhttp或者feign-httpclient依赖
设置feign.[httpclient|okhttp].enabled=true
7、OpenFeign多参数传递
@FeignClient(name="book-service") public interface BookService { @GetMapping("/bsn") public Book findBySn (@RequestParam("sn") String sn, @RequestParam("p1") String p1, @RequestParam("p2") String p2); } //http://book-service/bsn?sn=...&p1=xxx&p2=xxx
POST方式传递对象使用@RequestBody注解描述参数
GET方式将对象转换为Map后利用@RequestParam注解描述