javascript
Spring Boot----整合SpringCloud
首先比較一下Zookeeper和Eureka的區別?
1、CAP:C:強一致性,A:高可用性,P:分區容錯性(分布式中必須有)
?
CAP理論的核心是:一個分布式系統不可能同時很好的滿足一致性,可用性和分區容錯性這三個需求,因此,根據CAP原理將NoSQL數據庫分成了滿足CA原則、滿足CP原則和滿足AP原則三大類:
CA-單點集群,滿足一致性,可用性的系統,通常在可擴展性上不太強大。(RDMBS,關系型數據庫:mysql,sqlserver,oracle等)
CP-滿足一致性,分區容錯性的系統,通常性能不是特別高。(MongoDB,Redis,HBase等)
AP-滿足可用性,分區容錯性的系統,通常可能對一致性要求低一些。(CouchDB,DynamoDB等)
Zookeeper遵守CP原則
為什么說Zookeeper不保證高可用性? 原因在于當master節點(是某一臺Zookeeper服務器)因為網絡故障與其他節點(應該是注冊進入Zookeeper節點)失去聯系時,剩余節點會重新進行leader選
舉。問題在于,選舉leader的時間太長,30~120s,且選舉期間整個zk集群都是不可用的,這就導致在選舉期間注冊服務癱瘓。在云部署的環境下,因網絡問題使得zk集群失去master節點是較大概率會發生
的事,雖然服務能夠最終恢復,但是漫長的選舉時間導致的注冊長期不可用是不能容忍的。(總結:Zookeeper在某一時刻,只有一臺節點提供服務注冊發現(master節點),如果宕機了,此時其他的節點還
沒有選舉好,就會造成服務器癱瘓)
?
Eureka遵守AP原則
Eureka看明白了這一點,因此在設計時就優先保證可用性。Eureka各個節點都是平等的,幾個節點掛掉不會影響正常節點的工作,剩余的節點依然可以提供注冊和查詢服務。而Eureka的客戶端在向某
個Eureka注冊時候如果發現連接失敗,則會自動切換至其它節點,只要有一臺Eureka還在,就能保證注冊服務可用(保證可用性),只不過查到的信息可能不是最新的(不保證強一致性)。(總結:就是
各個節點的Eureka雖然都提供服務,但是數據不保證一致性,猜想:某一時刻還是只有一臺服務器提供注冊,只是當這臺服務器出現問題,此時其他的Eureka直接頂替他,但是此時的數據可能就沒有同步
就會造成數據的不一致性)
除此之外,Eureka還有一種自我保護機制,如果在15分鐘內超過85%的節點都沒有正常的心跳,那么Eureka就認為客戶端與注冊中心出現了網絡故障,此時會出現以下幾種情況:
1.Eureka不再從注冊列表中移除因為長時間沒收到心跳而應該過期的服務
2.Eureka仍然能夠接受新服務的注冊和查詢請求,但是不會被同步到其它節點上(即保證當前節點依然可用)
3.當網絡穩定時,當前實例新的注冊信息會被同步到其它節點中
?
mysql數據庫環境搭建
創建三個數據庫,為了實現每一個微服務都有一個獨立的數據庫
CREATE DATABASE javas1 CHARSET=utf8; CREATE DATABASE javas2 CHARSET=utf8; CREATE DATABASE javas3 CHARSET=utf8;CREATE TABLE USER( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(32) NOT NULL, dbSource VARCHAR(32) NOT NULL )INSERT INTO USER(NAME,dbSource) VALUES("1",DATABASE()); INSERT INTO USER(NAME,dbSource) VALUES("2",DATABASE()); INSERT INTO USER(NAME,dbSource) VALUES("3",DATABASE()); INSERT INTO USER(NAME,dbSource) VALUES("4",DATABASE()); INSERT INTO USER(NAME,dbSource) VALUES("5",DATABASE());
1、創建Eureka server(服務注冊中心)
?
1.1 application.properties
server:port: 8761eureka:instance:hostname: localhostclient://不把自己注冊到Euraka中register-with-eureka: false//不從eureka上獲取注冊信息fetch-registry: falseserviceUrl://單臺服務器填寫本機的地址(多臺Eureka server 服務器的集群看下面)defaultZone: http://localhost:8761/eureka1.2? @EnableEurekaServer 啟動
@EnableEurekaServer @SpringBootApplication public class EurekaApplication {public static void main(String[] args) {SpringApplication.run(EurekaApplication.class, args);} }1.3 訪問:http://localhost:8081/
?
2、創建 eureka client 服務提供者
?
數據庫等其他的配置省略
1、application.properties
server.port=8082 spring.application.name=provider//可顯示ip(鼠標停留在注冊的實例上) eureka.instance.prefer-ip-address=true eureka.client.service-url.defaultZone=http://localhost:8761/eureka //填寫Eureka server服務器地址,如果有多臺Eureka server服務器,就寫多個(用,分開)2、創建controller
@RestController public class TestController {@GetMapping("hellow")public String hellow(){return "hellow";} }3、啟動(可以改變端口,啟動多個provider),感覺最好加上@EnableEurekaClient注解,測試的時候沒加也沒問題
@SpringBootApplication public class ProviderApplication {public static void main(String[] args) {SpringApplication.run(ProviderApplication.class, args);}}4、Application就是我們配置的名字
如果需要修改Status中的值
eureka:instance:instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}} //可以修改
?
3、創建 eureka client 服務消費者
?
3.1 application.properties
server.port=80spring.application.name=consumer//注冊服務的時候使用ip進行注冊 eureka.instance.prefer-ip-address=true eureka.client.service-url.defaultZone=http://localhost:8761/eureka消費者如果不希望添加到Eureka中列表中,可以設置,但是如果此消費者被其他的消費者調用,就需要注冊到列表中(注意不添加到列表不代表不能從注冊列表獲取提供者的服務),注冊到列表中的目的,是我們可以通過列表中的application名字來訪問服務,而不是通過具體的IP了。
server.port=80spring.application.name=consumer//不把自己添加到Eureka列表中 eureka.client.register-with-eureka=false eureka.client.service-url.defaultZone=http://localhost:8761/eureka3.2 controller
@RestController public class ConsumerController {@Autowiredpublic RestTemplate restTemplate;@GetMapping("hellow")public String consumerhellow(){//通過http來訪問provider(Eureka提供的application名字,也是我們在提供者的配置的填寫的application.name)(url可以是生產者直接對外暴露的url,但是這樣就沒有負載均衡了)String forObject = restTemplate.getForObject("http://PROVIDER/hellow", String.class);return "consumer"+forObject;} }補充:RestTemplate(同步)使用:https://docs.spring.io/spring-framework/docs/5.1.9.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html,5.0之后RestTemplate不在添加新的東西了
后續可能使用WebClient(異步):https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/web-reactive.html#webflux-client
3.3 @EnableDiscoveryClient 和 RestTemplate ,啟動
@EnableDiscoveryClient //開啟服務發現功能 @SpringBootApplication public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}@LoadBalanced //使用負載均衡機制@Bean //注冊RestTemplatepublic RestTemplate restTemplate(){RestTemplate restTemplate = new RestTemplate();return restTemplate;} }3.3使用actuator來顯示應用信息
如果測試不行,記得清除target目錄,重新編譯
1、導入依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId><version>${spring-boot.version}</version></dependency>2、可以在父工程的pom中導入
<build><finalName>springcloud-depedences</finalName><resources><resource><directory>src/main/resources</directory><filtering>true</filtering></resource></resources><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><configuration><delimiters><delimiter>$</delimiter> //用$做分隔符</delimiters></configuration></plugin></plugins></build>3、applicaiton
info:app.name: zy.provider:8081company.name: www.xx.xx#取pom.xml中配置build.artifictId: $project.artifactId$ //project.artifactId會被替換成pom中<artifactId>xx</artifactId>build.version: $project.version$補充:如果使用${xx.xx},我們可以直接在配置文件中配置數據,就不用使用插件了
?
測試結果
?
4、搭建Eureka server 端集群
1、為了測試方便,在hosts文件夾中添加,添加多個域名(如果使用 localhost可能會出現問題,沒有測試)
127.0.0.1 eurekaserver8090.com 127.0.0.1 eurekaserver8091.com2、第一臺 eureka server 服務器配置(主要就是serviceUrl 改變了)
server:port: 8090eureka:instance:hostname: eurekaserver8090.comclient:register-with-eureka: falsefetch-registry: falseservice-url:#指定其他的eureka server服務器,多個服務用,分割defaultZone: http://eurekaserver8091.com:8091/eureka/3、第二臺 eureka server 服務器
server:port: 8091eureka:instance:hostname: eurekaserver8091.comclient:register-with-eureka: falsefetch-registry: falseserviceUrl:#指定其他的eureka server服務器ip地址,多個服務用,分割defaultZone: http://eurekaserver8090.com:8090/eureka/4、eureka client 配置:將所有的eureka客戶端(消費者和提供者)注冊到所有的eureka服務端中
eureka:instance:prefer-ip-address: trueinstance-id: 192.168.1.100:8081 //名字可以任意client:service-url:defaultZone: http://eurekaserver8090.com:8090/eureka/,http://eurekaserver8091.com:8091/eureka/ //添加部分:改為所有的Eureka集群ip
?
5、Ribbon負載均衡
RIbbon和Nginx區別:?https://www.cnblogs.com/toov5/p/9953971.html
Spring Cloud Ribbon是基于Netflix Ribbon實現的一套?客戶端(消費者,對于提供者來說是客戶端)? 負載均衡的工具。
概述:
負載均衡簡單的說就是將用戶的請求平攤的分配到多個服務上,從而達到系統的HA。
常見的負載均衡有軟件Nginx,LVS,硬件F5等。
相應的在中間件,例如:dubbo和SpringCloud中均給我們提供了負載均衡,SpringCloud的負載均衡算法可以自定義。
集中式LB:即在服務的消費方和提供方之間使用獨立的LB設施(可以是硬件,如F5(貴),也可以是軟件,如nginx),由該設施負責把訪問請求通過某種策略轉發至服務的提供方;
進程式LB:將LB邏輯集成到消費方,消費方從服務注冊中心獲知有哪些地址可用,然后自己再從這些地址中選擇出一個合適的服務器。
Ribbon就屬于進程內LB,它只是一個類庫,集成于消費方進程,消費方通過它來獲取到服務提供方的地址。
?
1、給eureka client 消費者添加依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId><version>${ribbon.version}</version></dependency>2、只需要使用@LoadBalanced注解即可(如果單單指使用輪詢算法的話,即使不使用ribbon插件,可以使實現負載均衡)
@Configuration public class RestTemplateConfig {@LoadBalanced@Beanpublic RestTemplate restTemplate(){return new RestTemplate();} }3、使用內置其他的算法
補充RetryRule:就是開始使用輪詢算法,如果某一臺服務器宕機了,當輪詢到調用宕機的服務器的時候,就會方法服務器錯誤,執行多次錯誤之后,ribbon就會選擇跳過這個服務,不在訪問宕機的服務器了。
?
使用??IRule,來切換其他內置算法
@Configuration public class RestTemplateConfig {@LoadBalanced@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}@Beanpublic IRule iRule(){return new RandomRule();} }4、使用自定義算法
4.1 使用?@RibbonClient
注意?CustomConfiguration.class 不能被它掃描到@ComponentScan,就是說讓不能放到和主啟動類一個目錄下(否則所有的服務共享這個負載均衡算法)
@RibbonClient(name = "PROVIDER", configuration = CustomConfiguration.class) //表示該消費者指對PROVIDER服務使用某一種算法 @EnableDiscoveryClient @SpringBootApplication public class SpringcloudConsumerApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudConsumerApplication.class, args);} }添加CustomConfiguration
package com.zy.myRule; //注意包名@Configuration public class CustomConfiguration {@Beanpublic IRule iRule(){return new MyRule(); //可以自定義算法} }需求:比如說每一個微服務訪問5次(模仿著RandomRule算法改的)
package com.zy.myRule;public class MyRule extends AbstractLoadBalancerRule {private static int a=0;//第x個服務器被訪問private static int b=0; //第a次被訪問public Server choose(ILoadBalancer lb, Object key) {if (lb == null) {return null;}Server server = null;while (server == null) {if (Thread.interrupted()) {return null;}List<Server> upList = lb.getReachableServers();List<Server> allList = lb.getAllServers();int serverCount = allList.size();if (serverCount == 0) {return null;}if(b<5){b++;}else {a++;b=1;if (a==upList.size()){a=0;}}server = upList.get(a);if (server == null) {Thread.yield();continue;}if (server.isAlive()) {return (server);}// Shouldn't actually happen.. but must be transient or a bug.server = null;Thread.yield();}return server;}protected int chooseRandomInt(int serverCount) {return ThreadLocalRandom.current().nextInt(serverCount);}@Overridepublic Server choose(Object key) {return choose(getLoadBalancer(), key);}@Overridepublic void initWithNiwsConfig(IClientConfig clientConfig) {// TODO Auto-generated method stub} }?
?
6、Feign負載均衡
概述:
客戶端(消費者,對于提供者來說是客戶端)? 負載均衡的工具。
由于Ribbon使用微服務名字獲得調用接口
而Feign使用的是接口+注解,獲得調用服務,體現在了面向接口編程,并且Feign繼承了Ribbon
一般Ribbon和Feign可以互相搭配使用
6.1、添加依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>6.2、定義接口
package com.zy.springcloudconsumer81.server;@FeignClient("PROVIDER") public interface FeiginServer {@GetMapping("/user/{id}")public User get(@PathVariable(value = "id") Integer id); }6.3、使用
package com.zy.springcloudconsumer81.controller;@RestController public class UserController {@Autowiredprivate FeiginServer feiginServer;@GetMapping("/user/get/{id}")public User get(@PathVariable(value = "id") Integer id){User user = deptClientServer.get(id);return user;} }?
注意:我們可以將接口放到一個公共的API模塊,利用?@ComponentScan(),來掃描這個包,但是實際測試的時候發現如果添加了這個注解,會造成自己的controller不能被訪問(具體原因還不清楚)
?
?
7、Hystrix斷路器
Hystrix是一個用于處理分布式系統的延遲和容錯的開源庫,在分布式系統里,許多依賴不可避免的會調用失敗,比如超時、異常等,Hystrix能夠保證在一個依賴出問題的情況下,不會導致整體服務失敗,避免級聯故障,以提高分布式系統的彈性。“斷路器”本身是一種開關裝置,當某個服務單元發生故障之后,通過斷路器的故障監控(類似熔斷保險絲),向調用方返回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者拋出調用方無法處理的異常,這樣就保證了服務調用方的線程不會被長時間、不必要地占用,從而避免了故障在分布式系統中的蔓延,乃至服務雪崩。
功能:
服務降級
服務熔斷
服務限流
接近實時的監控
?
測試服務熔斷
1、修改提供者(@HystrixCommand)
package com.zy.springcloudprovider8081.controller;@RestController public class UserController {@Autowiredprivate UserService userService;@HystrixCommand(fallbackMethod = "defaultStores")@GetMapping("/user/{id}")public User get(@PathVariable(value = "id",required = true) Integer id){User user = userService.get(id);int a = 1/0; //偽造錯誤return user;}public User defaultStores(Integer id){ //參數需要相同User user = new User();user.setName("錯誤了");return user;} }2、使用@EnableCircuitBreaker
package com.zy.springcloudprovider8081;//開啟注解 @EnableCircuitBreaker @EnableEurekaClient @SpringBootApplication public class SpringcloudProvider8081Application {public static void main(String[] args) {SpringApplication.run(SpringcloudProvider8081Application.class, args);} }測試服務降級
服務降級是在消費者端(客戶端)完成的
1、在客戶端定義一個接口實現FallbackFactory
package com.zy.springcloudconsumer81.server;@Component public class UserclientServiceFa1lbackFactory implements FallbackFactory<FeiginServer> {@Overridepublic FeiginServer create(Throwable throwable) {return new FeiginServer(){@Overridepublic User get(Integer id) {User user = new User();user.setId(id);user.setName("該服務已經停止.....請稍后訪問");return user;}};} }2、修改 @FeignClient 注解
package com.zy.springcloudconsumer81.server;//如果任何一個訪問出了問題,去執行UserclientServiceFa1lbackFactory相對應的方法; @FeignClient(value = "PROVIDER",fallbackFactory = UserclientServiceFa1lbackFactory.class) public interface FeiginServer {@GetMapping("/user/{id}")public User get(@PathVariable(value = "id") Integer id); }3、application(一定得添加),@EnableHystrix并不能替代下面的配置
feign:hystrix:enabled: true4、啟動
@EnableFeignClients @EnableDiscoveryClient @SpringBootApplication public class SpringcloudConsumer81Application {public static void main(String[] args) {SpringApplication.run(SpringcloudConsumer81Application.class, args);} }測試:
1、如果服務端配置了?fallbackMethod,會去調用服務端的fallback,自己的fallbackFactory方法不會被調用
2、fallbackFactory調用的前提1、服務端沒有配置 fallbackMethod,并且服務端發生了錯誤 2、或者。服務端直接停止服務(客戶端連接不上服務端)。
?
8、HystrixDashboard
1、新建一個module,或者用任何一個微服務做為HystrixDashboard
2、添加依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency>3、所有需要被監控的的微服務都需要監控依賴配置actuator
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId> </dependency>4、在被監控的微服務中配置application,可以直接include: "*",但是注意如果只寫include: hystrix.stream,那么info和health就訪問不了
management:endpoints:web:exposure:include:- info- health- hystrix.stream4.1測試
4.1.1 訪問http://192.168.1.100:8081/actuator/hystrix.stream,如果測試出現下面的結果
4.1.2 訪問被監控的微服務的任何controller(有可能需要訪問的是加了@HystrixCommand注解的方法)
?
4.1.3 訪問http://192.168.1.100:8081/actuator/hystrix.stream,表示成功(如果這一步沒有數據,會導致后面使用 HystrixDashboard 的時候出現Unable to connect to Command Metric Stream)
?
3、配置監控其他微服務的模塊,applicaiton
server:port: 90014、@EnableHystrixDashboard
@EnableHystrixDashboard @SpringBootApplication public class SpringcloudHystrixdashboardApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudHystrixdashboardApplication.class, args);} }5、使用儀表盤,下面配置網站,就是我們之前測試的網址。
6、詳細說明
?
?
?
8、zuul 路由網關
Zuul包含了對請求的路由和過濾兩個最主要的功能:
其中路由功能負責將外部請求轉發到具體的微服務實例上,是實現外部訪問統一入口的基礎而過濾器功能則負責對請求的處理過程進行干預,是實現請求校驗、服務聚合等功能的基礎.Zuul和Eureka進行整合,將Zuul自身注冊為Eureka服務治理下的應用,同時從Eureka中獲得其他微服務的消息,也即以后的訪問微服務都是通過Zuul跳轉后獲得。
注意:Zuul服務最終還是會注冊進Eureka
1、創建工程
2、主要額外添加依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>3、配置application
server:port: 9100#注冊到eureka服務堡列表中 eureka:client:service-url:defaultZone: http://eurekaserver8090.com:8090/eureka/,http://eurekaserver8091.com:8091/eureka/instance:instance-id: zuul-9100prefer-ip-address: truespring:application:name: zuul-getwayzuul:#(可以選擇不加)加上統一的公共前綴prefix: /zy/routes:#真實服務隱藏,使http://192.168.1.101:9100/provider/xx不生效(provider小寫),可以使用"*",忽略掉所有ignored-services: providerapi-a:#HTTP調用將/user轉發到PROVIDER服務path: /user/**#大小寫都可以service-id: PROVIDERapi-b:path: /xx/**service-id: XXX4、啟動
@EnableZuulProxy @SpringBootApplication public class SpringcloudZuulApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudZuulApplication.class, args);} }訪問:??http://192.168.1.101:9100/zy/user/user/1
?
9、Config分布式配置中心
微服務的配置有gitHub統一管理,但是這樣配置一旦修改,服務就得重啟,我們之后可以使用動態配置。
9.1、創建Config 服務端
9.1.1 在gitHub上克隆一個倉庫
9.1.2 克隆倉庫,創建application.yml,添加配置基本配置,上傳到gitHub上,注意:application.yml保存格式一定是utf-8,這些配置不是用來加載Config 服務端的,而是用來測試Config服務端時候可以讀取到gitHub倉庫配置
spring:profiles:active: dev --- spring:profiles: devapplication:name: springcloud-dev --- spring:profiles: testapplication:name: springcloud-dev9.1.3 創建一個model
9.1.4 主要添加依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-server</artifactId> </dependency>9.1.5 application.yml
spring:application:name: springcloud-configcloud:config:server:git:uri: https://github.com/zhengyanzy/springcloud-applicationConfig.gitusername: xxpassword: xx server:port: 92009.1.6? 啟動,添加EnableConfigServer
@EnableConfigServer @SpringBootApplication public class SpringcloudConfigApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudConfigApplication.class, args);} }9.1.7 測試訪問:http://192.168.1.101:9200/application-test.yml?、http://192.168.1.101:9200/application-dev.yml,測試是否可以連接gitHub并且訪問配置文件
9.2 、創建Config 客戶端(可以使用之前我們創建的model)
9.2.1 主要添加依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId> </dependency>9.2.2 將某一個model配置的application.yml,推送到gitHub上,取名provider-8081.yml,可以將該model中application.yml中的配置全部注釋掉,用來測試下面的配置是否成功
9.2.3 新建bootstrap.yml (bootstrap.yml中的配置會覆蓋application.yml配置)
spring:cloud:config:label: master#gitHub中的配置文件,沒有后綴名name: provider-8081#如果 provider-8081.yml包含了多個配置,可以通過下面的配置#profile: dev#Config 服務端uri: http://localhost:92009.2.4 正常啟動,啟動成功表示成功訪問到gitHub中的配置文件了
補充:Config 服務端應該是不需要注冊到eureka上的,畢竟eureka的配置也需要通過config server side來從gitHub獲取,所以config server side是最先啟動的。
轉載于:https://www.cnblogs.com/yanxiaoge/p/11399079.html
總結
以上是生活随笔為你收集整理的Spring Boot----整合SpringCloud的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java中怎么用代码打出ASCII码字符
- 下一篇: gmssl java_GMSSL编译运行