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接口調(diào)用
- 業(yè)務(wù)邏輯在 FacadeImpl 實(shí)現(xiàn)類中寫,Iservice實(shí)現(xiàn)類剿吻,Mapper接口不屑任何東西
- 數(shù)據(jù)庫實(shí)體對象是 XxxxxEntity
- 輸入對象為 BO
- 返回對象為VO
3. 服務(wù)注冊與發(fā)現(xiàn)
CAP理論
什么是CAP 拾弃?
- C : Consistency (強(qiáng)一致性)
- A : Availability (可用性)
- P : Partition tolerance (分區(qū)容錯(cuò)性)
Eureka , Zookeeper , Consul 比較
- Eureka : AP
- Consul : CP
- Zookeeper : CP
3.1 Eureka 服務(wù)注冊與發(fā)現(xiàn)
- Eureka Server
提供服務(wù)注冊,各個(gè)服務(wù)啟動后會在Server中進(jìn)行注冊羡疗,服務(wù)注冊表將會存儲所有可用服務(wù)節(jié)點(diǎn)的信息染服,可以在界面中看到。
-
Eureka Client
通過注冊中心進(jìn)行訪問叨恨,客戶端內(nèi)置一個(gè)使用輪詢(round-robin)算法的負(fù)載均衡器柳刮。在應(yīng)用啟動后會向Server發(fā)送默認(rèn)周期為30秒的心跳包,如果Server在多個(gè)心跳周期內(nèi)沒有收到某個(gè)節(jié)點(diǎn)的心跳i特碳,Server會將該節(jié)點(diǎn)從服務(wù)注冊表中移除(一般默認(rèn)90秒诚亚,3個(gè)心跳周期)。
-
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 # 表示我自己就是服務(wù)端站宗,不需要取檢索服務(wù) 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 # 表示我自己就是服務(wù)端,不需要取檢索服務(wù) eureka.client.fetch-registry=false eureka.client.service-url.defaultZone=http://eureka7001.com:7001/eureka/
-
-
cloud-provider-payment 服務(wù)注冊到 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 兩個(gè)服務(wù)注冊發(fā)現(xiàn)益愈,調(diào)用梢灭,服務(wù)名同一個(gè)
-
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 微服務(wù)單機(jī)版調(diào)用 cloud-provider-payment10010 服務(wù)
public static final String PAYMENT_URL="http://localhost:10010"; @Resource private RestTemplate restTemplate; @GetMapping("/consumer/payment/create/{serial}") public CommonResult<PaymentVO> create(@PathVariable("serial") String serial){ return restTemplate.getForObject(PAYMENT_URL+"/payment/post/"+serial,CommonResult.class); }
-
多個(gè)微服務(wù)調(diào)用模式:不能寫死服務(wù)請求地址夷家,可以通過服務(wù)名指定(多個(gè)微服務(wù)同一個(gè)服務(wù)名)
@LoadBalanced 配置 RestTemplate 負(fù)載均衡:讓應(yīng)用知道如何調(diào)用多個(gè)微服務(wù)
@Configuration public class ConsumerOrderConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
public static final String PAYMENT_URL="http://CLOUD-PAYMENT-SERVICE";
-
-
微服務(wù)界面展示的服務(wù)名,IP信息配置修改
# eureka 管理界面 STATUS 欄展示的名稱 eureka.instance.instance-id=paymentService10010 # 顯示IP地址(鼠標(biāo)浮動上去展示IP地址) eureka.instance.prefer-ip-address=true
-
-
Eureka 服務(wù)發(fā)現(xiàn) Discovery
-
添加組件
/** * 注入服務(wù)發(fā)現(xiàn)組件 * import org.springframework.cloud.client.discovery.DiscoveryClient; */ @Resource private DiscoveryClient discoveryClient;
-
模擬 服務(wù)發(fā)現(xiàn)敏释,打印獲取到的服務(wù)信息
@GetMapping("/payment/discovery") public Object discovery(){ // 獲取所有的微服務(wù)名 List<String> services = discoveryClient.getServices(); for (String service : services) { log.info("service=",service); } // 獲取指定微服務(wù)名下的實(shí)例库快,如CLOUD-PAYMENT-SERVICE服務(wù)名下有兩個(gè)實(shí)例微服務(wù) // cloud-provider-payment10010,cloud-provider-payment10011 List<ServiceInstance> 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 , 開啟服務(wù)發(fā)現(xiàn)機(jī)制钥顽。
-
-
Eureka 自我保護(hù)理論
自我保護(hù)模式下义屏,服務(wù)一旦注冊進(jìn)服務(wù)注冊表后,掛掉的服務(wù)不會立刻清掉蜂大。屬于AP理論分支闽铐。
-
如何禁止自我保護(hù)模式:
-
Eureka-Server7001 的 yml配置
# 關(guān)閉禁止自我保護(hù)模式 eureka.server.enable-self-preservation=false eureka.server.eviction-interval-timer-in-ms=2000
-
Eureka-Client :cloud-provider-payment10010 服務(wù)配置
# 修改 Eureka 客戶端向服務(wù)端發(fā)送心跳的時(shí)間間隔(默認(rèn)30秒,改成1秒) eureka.instance.lease-renewal-interval-in-seconds=1 # 收到最后一次心跳服務(wù)端等待的時(shí)間上限(默認(rèn)是90秒奶浦,改成2秒) eureka.instance.lease-expiration-duration-in-seconds=2
-
Eureka 目前很少使用
3.2 Zookeeper 服務(wù)注冊發(fā)現(xiàn)
-
zookeeper 是什么 兄墅?
zookeeper是分布式協(xié)調(diào)工具,可以完成注冊中心的功能澳叉。
-
zookeeper 安裝
centos7
zookeeper-3.4.9/bin
-
基本操作
# 關(guān)閉防火墻 systemctl stop firewalld
-
服務(wù)提供者:新建 cloud-provider-payment10012模塊,引入zookeeper客戶端依賴
<!-- 引入zookeeper客戶端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> </dependency> 如果提示 jar 包沖突錯(cuò)誤隙咸,排除掉apache自帶的zookeeper <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency>
-
修改主啟動類注解
@EnableDiscoveryClient 該注解用于向consul或zookeeper作為注冊中心時(shí)注冊服務(wù)使用
@SpringBootApplication @MapperScan("com.dc.scloud.mapper") @EnableDiscoveryClient public class ProviderPaymentApplication10012 { public static void main(String[] args) { SpringApplication.run(ProviderPaymentApplication10012.class); } }
-
修改 properties 文件
# 安裝 zookeeper工具的虛擬機(jī)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<String> paymentWithZK(){ String msg="spring cloud payment service ,port="+servicePort+ ", "+UUID.randomUUID().toString(); CommonResult<String> stringCommonResult = new CommonResult<>(200,msg,msg); return stringCommonResult; } }
-
服務(wù)消費(fèi)者: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<PaymentVO> queryPayment(@PathVariable("id") String id){ return restTemplate.getForObject(PAYMENT_URL+"/payment/zk/list",CommonResult.class); } }
zookeeper 中的服務(wù)名區(qū)分大小寫的
-
3.3 Consul 服務(wù)注冊與發(fā)現(xiàn)
-
什么是 Consul ?
consul是一套分布式服務(wù)發(fā)現(xiàn)和配置管理系統(tǒng)成洗,提供了服務(wù)之間的服務(wù)治理五督,配置中心,控制總線等泌枪。
-
服務(wù)提供者注冊進(jìn)consul:cloud-providerconsul-payment10016
-
pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency>
-
application.properties
server.port=10016 spring.application.name=cloud-payment-service10016 # 單機(jī) 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<String> paymentWithZK(){ String msg="spring cloud payment service ,port="+servicePort+ ", "+UUID.randomUUID().toString(); CommonResult<String> stringCommonResult = new CommonResult<>(200,msg,msg); return stringCommonResult; } }
-
啟動類
@SpringBootApplication @EnableDiscoveryClient public class ProviderConsulPayment10016 { public static void main(String[] args) { SpringApplication.run(ProviderConsulPayment10016.class); } }
-
-
服務(wù)消費(fèi)者注冊進(jìn)consul:cloud-consumerconsul-order10008
-
pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency>
-
properties
server.port=10008 spring.application.name=cloud-consumerconsul-order10008 # 單機(jī) 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<PaymentVO> 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 負(fù)載均衡 cloud-consumer-order
4.1 理論
Spring Cloud Ribbon 是基于 Netflix Ribbon 實(shí)現(xiàn)的一套客戶端負(fù)載均衡的工具概荷。提供客戶端的軟件負(fù)載均衡算法和服務(wù)調(diào)用。
-
LB 負(fù)載均衡(Load Balance)是什么碌燕?
將用戶的請求平攤到多個(gè)服務(wù)上误证,常見的負(fù)載軟件有:Nginx,LVS修壕;硬件F5等愈捅。
-
Ribbon是本地負(fù)載均衡
在調(diào)用微服務(wù)接口時(shí),會在注冊中心上獲取注冊信息服務(wù)列表緩存到JVM本地慈鸠,在本地實(shí)現(xiàn)RPC遠(yuǎn)程服務(wù)調(diào)用技術(shù)蓝谨。
-
Nginx是服務(wù)端負(fù)載均衡
所有的請求都交給Nginx,由Nginx實(shí)現(xiàn)請求轉(zhuǎn)發(fā)青团。
4.2 ribbon負(fù)載均衡和Rest調(diào)用
spring-cloud-starter-netflix-eureka-client 已經(jīng)集成了 ribbon 依賴
-
Ribbon 默認(rèn)時(shí) 輪詢機(jī)制
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
4.3 ribbon 替換負(fù)載規(guī)則
Ribbon 規(guī)則替換配置類不能在主啟動類所在包及其子包路徑下譬巫。
新建包:package com.dc.myrule;
-
隨機(jī)算法:自定義配置類
@Configuration public class MyRibbonRule { /** * 配置隨機(jī)算法進(jìn)行負(fù)載 * @return */ @Bean public IRule myRule(){ return new RandomRule(); } }
-
@RibbonClient 主啟動類指定對某個(gè)微服務(wù)設(shè)置某種負(fù)載策略
@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
- 負(fù)載均衡算法:
- rest接口第幾次請求數(shù) % 服務(wù)器集群總數(shù) = 實(shí)際調(diào)用服務(wù)器位置下標(biāo) ;
- 每一次服務(wù)重啟后rest接口計(jì)數(shù)從1開始督笆;
5. OpenFeign
5.1 什么是 Feign 芦昔?
Feign 是一個(gè)聲明式WebService客戶端。使用方法是:定義一個(gè)服務(wù)接口娃肿,然后在其上添加注解咕缎。Feign也支持可插拔式的編碼器和解碼器珠十。Spring Cloud 對Feign進(jìn)行了封裝,使其支持了SpringMVC標(biāo)準(zhǔn)注解和HttpMessageConverters凭豪。Feign可以與Eureka和Ribbon組合使用支持負(fù)載均衡焙蹭。
-
Feign 與 OpenFeign 的比較
Feign OpenFeign OpenFeign是 SpringCloud在Feign基礎(chǔ)上支持了SpringMVC的注解。 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
5.2 Feign 服務(wù)調(diào)用
新建 cloud-consumeropenfeign-order10008 微服務(wù)
-
注入依賴pom
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
-
開啟 Feign
@SpringBootApplication @EnableFeignClients public class ConsumerOpenFeignOrderApplication { public static void main(String[] args) { SpringApplication.run(ConsumerOpenFeignOrderApplication.class); } }
-
定義業(yè)務(wù)類的接口
@Component @FeignClient("CLOUD-PAYMENT-SERVICE") // 指定請求調(diào)用哪一個(gè)微服務(wù) public interface IPaymentFeignService { @GetMapping(value = "/payment/list/{id}") // CLOUD-PAYMENT-SERVICE mapper 地址 public CommonResult<PaymentVO> 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<PaymentVO> getPaymentVOById(@PathVariable("id") String id){ return iPaymentFeignService.getParmentById(id); } }
5.3 Feign 超時(shí)控制
默認(rèn)Feign客戶端只等待1秒嫂伞,但是服務(wù)端處理時(shí)間超過1秒孔厉,直接發(fā)會報(bào)錯(cuò)。
在 properties 中配置默認(rèn)設(shè)置:
ribbon.ReadTimeout=5000
ribbon.ConnectTimeout=5000
5.4 Feign 日志增強(qiáng)
-
自定義配置類
@Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }
-
配置 yml / properties
# 開啟 feign 日志 : 以哪一種日志級別監(jiān)控哪一個(gè)feign接口 logging.level.com.dc.scloud.service.IPaymentFeignService=debug