Spring Cloud Alibaba & H
1. 建表SQL
1.1 支付模块
1.1.1 payment
create table payment(
id varchar(64) not null,
serial varchar(200) default '',
primary key(id)
);
1.1.2
2. Mybatis-Plus-Generator
2.1 使用要求
- 尽量不自己写SQL
- 使用plus提供的IService接口,通过门面IFacade接口调用
- 业务逻辑在 FacadeImpl 实现类中写,Iservice实现类,Mapper接口不屑任何东西
- 数据库实体对象是 XxxxxEntity
- 输入对象为 BO
- 返回对象为VO
3. 服务注册与发现
CAP理论
什么是CAP ?
- C : Consistency (强一致性)
- A : Availability (可用性)
- P : Partition tolerance (分区容错性)
Eureka , Zookeeper , Consul 比较
- Eureka : AP
- Consul : CP
- Zookeeper : CP
3.1 Eureka 服务注册与发现
- Eureka Server
提供服务注册,各个服务启动后会在Server中进行注册,服务注册表将会存储所有可用服务节点的信息,可以在界面中看到。
-
Eureka Client
通过注册中心进行访问,客户端内置一个使用轮询(round-robin)算法的负载均衡器。在应用启动后会向Server发送默认周期为30秒的心跳包,如果Server在多个心跳周期内没有收到某个节点的心跳i,Server会将该节点从服务注册表中移除(一般默认90秒,3个心跳周期)。
-
Eureka 集群
-
修改 C/Windows/System32/drivers/etc/hosts 配置
127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com
-
改写yml配置,eureka server互相注册
-
Eureka Server 7001
server.port=7001 spring.application.name=cloud-eureka-server7001 eureka.instance.hostname=eureka7001.com # false 表示不想注册中心注册自己 eureka.client.register-with-eureka=false # 表示我自己就是服务端,不需要取检索服务 eureka.client.fetch-registry=false eureka.client.service-url.defaultZone=http://eureka7002.com:7002/eureka/
-
Eureka Server 7002
server.port=7002 spring.application.name=cloud-eureka-server7002 eureka.instance.hostname=eureka7002.com # false 表示不想注册中心注册自己 eureka.client.register-with-eureka=false # 表示我自己就是服务端,不需要取检索服务 eureka.client.fetch-registry=false eureka.client.service-url.defaultZone=http://eureka7001.com:7001/eureka/
-
-
cloud-provider-payment 服务注册到 Eureka Server 集群上
eureka.client.register-with-eureka=true eureka.client.fetch-registry=true eureka.client.service-url.defaultZone=http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
-
支付模块10010 和 10011 两个服务注册发现,调用,服务名同一个
-
cloud-provider-payment10010
server.port=10010 spring.application.name=cloud-payment-service
-
cloud-provider-payment10011
server.port=10011 spring.application.name=cloud-payment-service
-
cloud-consumer-order 微服务单机版调用 cloud-provider-payment10010 服务
public static final String PAYMENT_URL="http://localhost:10010"; @Resource private RestTemplate restTemplate; @GetMapping("/consumer/payment/create/{serial}") public CommonResult
create(@PathVariable("serial") String serial){ return restTemplate.getForObject(PAYMENT_URL+"/payment/post/"+serial,CommonResult.class); } -
多个微服务调用模式:不能写死服务请求地址,可以通过服务名指定(多个微服务同一个服务名)
@LoadBalanced 配置 RestTemplate 负载均衡:让应用知道如何调用多个微服务
@Configuration public class ConsumerOrderConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
public static final String PAYMENT_URL="http://CLOUD-PAYMENT-SERVICE";
-
-
微服务界面展示的服务名,IP信息配置修改
# eureka 管理界面 STATUS 栏展示的名称 eureka.instance.instance-id=paymentService10010 # 显示IP地址(鼠标浮动上去展示IP地址) eureka.instance.prefer-ip-address=true
-
-
Eureka 服务发现 Discovery
-
添加组件
/** * 注入服务发现组件 * import org.springframework.cloud.client.discovery.DiscoveryClient; */ @Resource private DiscoveryClient discoveryClient;
-
模拟 服务发现,打印获取到的服务信息
@GetMapping("/payment/discovery") public Object discovery(){ // 获取所有的微服务名 List
services = discoveryClient.getServices(); for (String service : services) { log.info("service=",service); } // 获取指定微服务名下的实例,如CLOUD-PAYMENT-SERVICE服务名下有两个实例微服务 // cloud-provider-payment10010,cloud-provider-payment10011 List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); for (ServiceInstance instance : instances) { log.info("instance=",instance); log.info(instance.getInstanceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri()); } return discoveryClient; } 在主启动类上添加注解 @EnableDiscoveryClient , 开启服务发现机制。
-
-
Eureka 自我保护理论
自我保护模式下,服务一旦注册进服务注册表后,挂掉的服务不会立刻清掉。属于AP理论分支。
-
如何禁止自我保护模式:
-
Eureka-Server7001 的 yml配置
# 关闭禁止自我保护模式 eureka.server.enable-self-preservation=false eureka.server.eviction-interval-timer-in-ms=2000
-
Eureka-Client :cloud-provider-payment10010 服务配置
# 修改 Eureka 客户端向服务端发送心跳的时间间隔(默认30秒,改成1秒) eureka.instance.lease-renewal-interval-in-seconds=1 # 收到最后一次心跳服务端等待的时间上限(默认是90秒,改成2秒) eureka.instance.lease-expiration-duration-in-seconds=2
-
Eureka 目前很少使用
3.2 Zookeeper 服务注册发现
-
zookeeper 是什么 ?
zookeeper是分布式协调工具,可以完成注册中心的功能。
-
zookeeper 安装
centos7
zookeeper-3.4.9/bin
-
基本操作
# 关闭防火墙 systemctl stop firewalld
-
服务提供者:新建 cloud-provider-payment10012模块,引入zookeeper客户端依赖
org.springframework.cloud spring-cloud-starter-zookeeper-discovery org.springframework.cloud spring-cloud-starter-zookeeper-discovery org.apache.zookeeper zookeeper -
修改主启动类注解
@EnableDiscoveryClient 该注解用于向consul或zookeeper作为注册中心时注册服务使用
@SpringBootApplication @MapperScan("com.dc.scloud.mapper") @EnableDiscoveryClient public class ProviderPaymentApplication10012 { public static void main(String[] args) { SpringApplication.run(ProviderPaymentApplication10012.class); } }
-
修改 properties 文件
# 安装 zookeeper工具的虚拟机IP spring.cloud.zookeeper.connect-string=192.168.111.144:2181
-
修改 controller
@Slf4j @RestController public class PaymentController { @Autowired private IPaymentFacade iPaymentFacade; @Value("${server.port}") private String servicePort; @GetMapping("/payment/zk/list") public CommonResult
paymentWithZK(){ String msg="spring cloud payment service ,port="+servicePort+ ", "+UUID.randomUUID().toString(); CommonResult stringCommonResult = new CommonResult<>(200,msg,msg); return stringCommonResult; } } -
服务消费者:cloud-consumerzk-order10008
-
启动类配置
@SpringBootApplication @EnableDiscoveryClient public class ConsumerZKOrderApplication10008 { public static void main(String[] args) { SpringApplication.run(ConsumerZKOrderApplication10008.class); } }
-
controller
@RestController @Slf4j public class OrderController { //public static final String PAYMENT_URL="http://localhost:10010"; public static final String PAYMENT_URL="http://cloud-provider-payment10012"; @Resource private RestTemplate restTemplate; @GetMapping("/consumer/payment/query/{id}") public CommonResult
queryPayment(@PathVariable("id") String id){ return restTemplate.getForObject(PAYMENT_URL+"/payment/zk/list",CommonResult.class); } } zookeeper 中的服务名区分大小写的
-
3.3 Consul 服务注册与发现
-
什么是 Consul ?
consul是一套分布式服务发现和配置管理系统,提供了服务之间的服务治理,配置中心,控制总线等。
-
服务提供者注册进consul:cloud-providerconsul-payment10016
-
pom.xml
org.springframework.cloud spring-cloud-starter-consul-discovery -
application.properties
server.port=10016 spring.application.name=cloud-payment-service10016 # 单机 spring.cloud.consul.host=localhost spring.cloud.consul.port=8500 spring.cloud.consul.discovery.service-name=${spring.application.name}
-
controller
@Slf4j @RestController public class PaymentController { @Value("${server.port}") private String servicePort; @GetMapping("/payment/consul/list") public CommonResult
paymentWithZK(){ String msg="spring cloud payment service ,port="+servicePort+ ", "+UUID.randomUUID().toString(); CommonResult stringCommonResult = new CommonResult<>(200,msg,msg); return stringCommonResult; } } -
启动类
@SpringBootApplication @EnableDiscoveryClient public class ProviderConsulPayment10016 { public static void main(String[] args) { SpringApplication.run(ProviderConsulPayment10016.class); } }
-
-
服务消费者注册进consul:cloud-consumerconsul-order10008
-
pom.xml
org.springframework.cloud spring-cloud-starter-consul-discovery -
properties
server.port=10008 spring.application.name=cloud-consumerconsul-order10008 # 单机 spring.cloud.consul.host=localhost spring.cloud.consul.port=8500 spring.cloud.consul.discovery.service-name=${spring.application.name}
-
controller
@RestController @Slf4j public class OrderController { //public static final String PAYMENT_URL="http://localhost:10010"; public static final String PAYMENT_URL="http://cloud-payment-service10016"; @Resource private RestTemplate restTemplate; @GetMapping("/consumer/consul/query") public CommonResult
queryPayment(){ return restTemplate.getForObject(PAYMENT_URL+"/payment/consul/list",CommonResult.class); } } -
MainApplication.class
@SpringBootApplication @EnableDiscoveryClient public class ProviderConsulPayment10016 { public static void main(String[] args) { SpringApplication.run(ProviderConsulPayment10016.class); } }
-
4. Ribbon 负载均衡 cloud-consumer-order
4.1 理论
Spring Cloud Ribbon 是基于 Netflix Ribbon 实现的一套客户端负载均衡的工具。提供客户端的软件负载均衡算法和服务调用。
-
LB 负载均衡(Load Balance)是什么?
将用户的请求平摊到多个服务上,常见的负载软件有:Nginx,LVS;硬件F5等。
-
Ribbon是本地负载均衡
在调用微服务接口时,会在注册中心上获取注册信息服务列表缓存到JVM本地,在本地实现RPC远程服务调用技术。
-
Nginx是服务端负载均衡
所有的请求都交给Nginx,由Nginx实现请求转发。
4.2 ribbon负载均衡和Rest调用
spring-cloud-starter-netflix-eureka-client 已经集成了 ribbon 依赖
-
Ribbon 默认时 轮询机制
org.springframework.cloud spring-cloud-starter-netflix-eureka-client
4.3 ribbon 替换负载规则
Ribbon 规则替换配置类不能在主启动类所在包及其子包路径下。
新建包:package com.dc.myrule;
-
随机算法:自定义配置类
@Configuration public class MyRibbonRule { /** * 配置随机算法进行负载 * @return */ @Bean public IRule myRule(){ return new RandomRule(); } }
-
@RibbonClient 主启动类指定对某个微服务设置某种负载策略
@SpringBootApplication @EnableEurekaClient @RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MyRibbonRule.class) public class ConsumerOrderApplication { public static void main(String[] args) { SpringApplication.run(ConsumerOrderApplication.class); } }
4.4 轮询算法原理 RoundRobinRule
- 负载均衡算法:
- rest接口第几次请求数 % 服务器集群总数 = 实际调用服务器位置下标 ;
- 每一次服务重启后rest接口计数从1开始;
5. OpenFeign
5.1 什么是 Feign ?
Feign 是一个声明式WebService客户端。使用方法是:定义一个服务接口,然后在其上添加注解。Feign也支持可插拔式的编码器和解码器。Spring Cloud 对Feign进行了封装,使其支持了SpringMVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用支持负载均衡。
-
Feign 与 OpenFeign 的比较
Feign OpenFeign OpenFeign是 SpringCloud在Feign基础上支持了SpringMVC的注解。 org.springframework.cloud spring-cloud-starter-feign org.springframework.cloud spring-cloud-starter-openfeign
5.2 Feign 服务调用
新建 cloud-consumeropenfeign-order10008 微服务
-
注入依赖pom
org.springframework.cloud spring-cloud-starter-openfeign org.springframework.cloud spring-cloud-starter-netflix-eureka-client -
开启 Feign
@SpringBootApplication @EnableFeignClients public class ConsumerOpenFeignOrderApplication { public static void main(String[] args) { SpringApplication.run(ConsumerOpenFeignOrderApplication.class); } }
-
定义业务类的接口
@Component @FeignClient("CLOUD-PAYMENT-SERVICE") // 指定请求调用哪一个微服务 public interface IPaymentFeignService { @GetMapping(value = "/payment/list/{id}") // CLOUD-PAYMENT-SERVICE mapper 地址 public CommonResult
getParmentById(@PathVariable("id") String id); } -
定义Controller 层
@ResponseBody @RestController @Slf4j public class FeignOrderController { @Resource private IPaymentFeignService iPaymentFeignService; @GetMapping(value = "/consumer/order/feign/list/{id}") public CommonResult
getPaymentVOById(@PathVariable("id") String id){ return iPaymentFeignService.getParmentById(id); } }
5.3 Feign 超时控制
默认Feign客户端只等待1秒,但是服务端处理时间超过1秒,直接发会报错。
在 properties 中配置默认设置:
ribbon.ReadTimeout=5000
ribbon.ConnectTimeout=5000
5.4 Feign 日志增强
-
自定义配置类
@Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }
-
配置 yml / properties
# 开启 feign 日志 : 以哪一种日志级别监控哪一个feign接口 logging.level.com.dc.scloud.service.IPaymentFeignService=debug