首頁>技術>

此篇內容較長。

一、關於微服務

當單體應用越來越大的時候,一個小的改動就要重新編譯打包部署(空間和時間都會增大),在這個過程中,服務是完全不能對外提供任何服務的,而微服務僅更新需要更新的服務,對其他服務的訪問是不會受影響的。

這時我們要將單體應用按業務進行拆分,這就是微服務,同是微服務可以部署在不同的伺服器中,同一個微服務可以複製N份,這就是分散式,因此微服務是分散式的基礎。

兩個微服務之間進行通訊,一般有兩種協議,HTTP協議和RPC協議,HTTP協議是長連結的,網路消耗上比RPC要多,不過HTTP是無狀態的,不同的微服務可以採用不同的開發語言,只要對外提供的是REST風格就能進行相互通訊。

springcloud基於HTTP協議,而dubbo基於RPC協議。

springcloud的基礎是springboot,因此每一個微服務都可以看成是一個微小的單體應用。

將應用拆分成單體應用後,構成微服務提供者和微服務消費者,然後使用框架中的輔助性功能,服務和發現註冊中心、負載均衡、斷路器、閘道器、配置中心。

二、微服務工程的構建1、新建maven父工程

pom檔案

pom檔案

@Data@Accessors(chain = true)  //實體類可以鏈式呼叫@NoArgsConstructor   //無參構造@AllArgsConstructor //全參構造public class Person implements Serializable {    private int id;    private String name;    private int age;    @JsonIgnore  //密碼序列化被忽略    private String password;    //增加一個構造    public Person(String name, int age) {        this.name = name;        this.age = age;    }}

釋出此公共模組,clean------install,當看到成功後

然後觀察父工程的pom檔案,會多出一個modules節點,同樣,以後每建立一個微服務,其微服務的artifactId名稱都會出現在父工程的modules節點中。

<modules>        <module>microservice-cloud-api</module></modules>
3、新建微服務提供者8001

pom檔案

#服務提供商品server.port=8001 #資料庫連線配置spring.datasource.username=rootspring.datasource.password=XXXXspring.datasource.url=jdbc:mysql://localhost:3306/test

當前專案結構,資料庫框架採用的是Mybatis-Plus,配置好了直接採用程式碼化的sql拼接

PersonController類

@RestController@RequestMapping("/user")public class PersonController {    @Autowired    private PersonService personService;    @GetMapping("/list")    public List<Person> list() {        return personService.getList();    }    @GetMapping("/{id}")    public Person getById(@PathVariable int id){        return personService.getPersonById(id);    }    @GetMapping("/{name}/{age}")    public int insert(@PathVariable String name,@PathVariable String age){        return personService.insert(name,age);    }}
4、新建微服務消費者80

pom檔案

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <parent>        <artifactId>microservice-cloud</artifactId>        <groupId>icu.woodlum.cn</groupId>        <version>0.0.1-SNAPSHOT</version>    </parent>    <modelVersion>4.0.0</modelVersion>    <artifactId>microservice-cloud-consummer</artifactId>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>icu.woodlum.cn</groupId>            <artifactId>microservice-cloud-api</artifactId>            <version>0.0.1-SNAPSHOT</version>        </dependency>    </dependencies></project>

application.properties

#設定埠server.port=80

當前專案結構

配置RestTemplate----------MyConfig.class

@Configurationpublic class MyConfig {    @Bean    public RestTemplate getRestTemplate(){        return new RestTemplate();    }}

ConsummerController控制類,透過restTemplate.getForObject方法,遠端呼叫8001埠服務中的控制器方法。

@RestControllerpublic class ConsummerController {    //設定RestTemplate呼叫地址字首    private static final String REST_URL_PRE = "http://127.0.0.1:8001";    private RestTemplate restTemplate;    public ConsummerController(RestTemplate restTemplate) {        this.restTemplate = restTemplate;    }    @GetMapping("/list")    public List<Person> list() {        return restTemplate.getForObject(REST_URL_PRE + "/user/list", List.class);    }    @GetMapping("/{id}")    public Person getById(@PathVariable int id){        return restTemplate.getForObject(REST_URL_PRE + "/user/{id}",                Person.class,id);    }    @GetMapping("/add/{name}/{age}")    public int insert(@PathVariable("name") String name,@PathVariable("age") String age){        Person person = new Person(name, Integer.parseInt(age));        return restTemplate.getForObject(REST_URL_PRE + "/user/{name}/{age}",                Integer.class,person.getName(),person.getAge());    }}

依次啟動提供者和消費者服務

測試成功

三、服務和發現註冊中心(Eureka)

透過上面的兩個微服務(提供者和消費者)可以發現,消費者透過IP:埠來呼叫消費者的控制器,耦合性太強,如果提供者的IP或埠發生變化,又或分散式提供多個提供者,這時直接呼叫IP字首的方法就不可用,因此我們需要一箇中間伺服器,透過中間伺服器來配置,消費者就不需要關心提供者的具體位置資訊,透過提供者的名稱自動獲取所在的伺服器位置,然後來進行呼叫。

這個就像網際網路中的域名解析伺服器,比如百度網站,其伺服器可能是多個,而且在不同的位置就會有多個IP,但是我們訪問的時候並不需要關心,我們只需要在瀏覽器位址列中輸入www.baidu.com即可,瀏覽器會訪問IP解析伺服器,從中選擇一個最優的伺服器進行訪問,服務和發現註冊中心就相當於這個IP域名解析伺服器,根據微服務名稱和規則來合理選擇在服務中心註冊的微服務。

Eureka現在劃歸於netflix專案下了,從其maven座標可以看出,之前的在mvn網站上已經標記為過時。

1、新建Eureka分散式服務註冊中心7001和7002

pom檔案

為了本地測試多服務註冊中心,我們需要在Hosts檔案中新增:

127.0.0.1 www.woodlum7001.icu

127.0.0.1 www.woodlum7002.icu

server.port=7001#server.port=7002 #註冊中心主機名eureka.instance.hostname=www.woodlum7001.icu#eureka.instance.hostname=www.woodlum7002.icu #不註冊自身eureka.client.register-with-eureka=false#不檢索自身eureka.client.fetch-registry=false #單註冊中心#eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/#分散式註冊中心需要互相註冊eureka.client.service-url.defaultZone=http://www.woodlum7002.icu:7002/eureka/#eureka.client.service-url.defaultZone=http://www.woodlum7001.icu:7001/eureka/ #關閉自我保護,預設為true,超過85%服務掉線的時候,註冊中心不會移除掉線的例項#以保證服務的可用性,AP原則,服務可用性和容錯性,關閉在開發階段中使用,生產中建議使用預設#Renews/Renews threshold  預設0.85,小於此則會進行保護模式,註冊的客戶端不會刪除eureka.server.enable-self-preservation=false

在主程式中啟用Eureka伺服器

@SpringBootApplication//啟用Eureka伺服器,同理EurekaService7002@EnableEurekaServerpublic class EurekaService7001 {    public static void main(String[] args) {        SpringApplication.run(EurekaService7001.class,args);    }}
2、改進服務提供者8001

maven中增座標

重點:分散式多副本提供微服務,spring.application.name此名稱完全一致,因為消費者是按微服務名稱來查詢的

#服務提供商品server.port=8001#Eureka註冊地址,多eurika註冊中心,地址用,隔開eureka.client.service-url.defaultZone=http://www.woodlum7001.icu:7001/eureka/,http://www.woodlum.icu7002:7002/eureka/#重點:客戶端例項名稱,Eureka中會顯示,且顯示為全大寫,# 分散式多副本提供微服務,此名稱完全一致,因為消費者是按微服務名稱來查詢的spring.application.name=mircroservice-cloud-provider #Status中自定義服務名稱資訊eureka.instance.instance-id=microservice-cloud-provider:8001#訪問路徑可以顯示IP地址,瀏覽器左下角顯示Ip而非localhosteureka.instance.prefer-ip-address=true  #http://192.168.0.100:8001/actuator/info頁面資訊設定info.provider.name = microservice-cloud-provider-8001info.company.name = icu.woodlum.cn#獲取pom中節點資訊,注意,如果父pom中build中定界符設定為$,要使用@才能正常讀取#可能是新版本問題,當前工程actuator為2.3.4info.build.artifactId = @[email protected] = @project.modelVersion@ #資料庫連線spring.datasource.username=rootspring.datasource.password=XXXXspring.datasource.url=jdbc:mysql://localhost:3306/test

修改啟動類

@SpringBootApplication//啟動Eureka客戶端@EnableEurekaClientpublic class Provider8001 {    public static void main(String[] args) {        SpringApplication.run(Provider8001.class,args);    }}

分別啟動服務中心7001、7002和服務提供8001

訪問http://www.woodlum7001.icu:7001/和http://www.woodlum7002.icu:7002/

訪問instance-id連結

3、啟用Discovery服務發現元件

修改服務提供者的控制器

@RestController@RequestMapping("/user")public class PersonController {    // 服務發現    @Autowired    private DiscoveryClient client;     @GetMapping("/discovery")    public Object discovery(){       // 獲取服務中心的所有微服務名稱        List<String> list = client.getServices();        list.forEach(e -> {            System.out.println(e);            //以微服務名稱例項化微服務            List<ServiceInstance> instances = client.getInstances(e);            //獲取微服務例項的屬性            instances.forEach(l -> {                System.out.println(l.getInstanceId() + "|" + l.getHost() + "|" + l.getPort() + "|" + l.getUri() + "|" + l.getScheme() + "|" + l.getMetadata());            });        });        return this.client;    } }

啟動器中啟用服務發現

@SpringBootApplication@EnableEurekaClient//啟用服務發現@EnableDiscoveryClientpublic class Provider8001 {    public static void main(String[] args) {        SpringApplication.run(Provider8001.class,args);    }}

訪問服務發現服務

控制檯輸入:

mircroservice-cloud-providermicroservice-cloud-provider:8001|192.168.0.100|8001|http://192.168.0.100:8001|http|{management.port=8001, jmx.port=55787}

同理建立微服務提供者8002

四、Ribbon負載均衡

當服務提供者有多個時,消費者如何去選擇相應的微服務?負載均衡就是處理消費者對於微服務請求的分配。

Ribbon整合在Eureka中,因此我們不需要再引入相關maven座標。

Ribbon是客戶端的負載均衡,因此我們只需要改進消費服務。

1、Ribbon負載均衡的使用

application.properties檔案

server.port=80#消費方不註冊自己,但是會獲取服務eureka.client.register-with-eureka=false#預設獲取服務eureka.client.fetch-registry=true#eureka服務地址eureka.client.service-url.defaultZone=http://www.woodlum7001.icu:7001/eureka/,http://www.woodlum.icu7002:7002/eureka/

配置負載均衡@LoadBalanced開啟,預設為輪詢方式

@Configurationpublic class MyConfig {    @Bean    // 開啟LB (負載均衡)    @LoadBalanced    public RestTemplate getRestTemplate(){        return new RestTemplate();    }}

修改消費者控制器

@RestControllerpublic class ConsummerController {    // ribbon負載均衡下,訪問的是微服務名稱    private static final String REST_URL_PRE = "http://MIRCROSERVICE-CLOUD-PROVIDER";    //設定Rest訪問地址    //private static final String REST_URL_PRE = "http://127.0.0.1:8001";        private RestTemplate restTemplate;    public ConsummerController(RestTemplate restTemplate) {        this.restTemplate = restTemplate;    }    @GetMapping("/list")    public List<Person> list() {        return restTemplate.getForObject(REST_URL_PRE + "/user/list", List.class);    }    @GetMapping("/{id}")    public Person getById(@PathVariable int id){        return restTemplate.getForObject(REST_URL_PRE + "/user/{id}",                Person.class,id);    }    @GetMapping("/add/{name}/{age}")    public int insert(@PathVariable("name") String name,@PathVariable("age") String age){        Person person = new Person(name, Integer.parseInt(age));        return restTemplate.getForObject(REST_URL_PRE + "/user/{name}/{age}",                Integer.class,person.getName(),person.getAge());    }    @GetMapping("/discovery")    public Object discovery(){        return restTemplate.getForObject(REST_URL_PRE + "/user/discovery",Object.class);    }}

修改啟動類

@SpringBootApplication//啟用Eureka客戶端@EnableEurekaClientpublic class Consummer {    public static void main(String[] args) {        SpringApplication.run(Consummer.class, args);    }}

啟動專案

測試

2、Ribbon規則演算法:

預設為輪詢方式,多個服務提供者按順序會依次訪問

Ribbon規則有個介面IRule

RoundRobinRule

輪詢,依次呼叫服務提供者,預設的方式

RandomRule——隨機,多服務提供者隨機呼叫AvailabilityFilteringRule——先過濾掉由於故障處於斷路器跳閘狀態的服務,還有併發連線超過閾值的服務,然後對剩餘的服務列表進行輪詢WeightedResponseTimeRule——根據平均響應時間計算所有伺服器的權重響應時間越快,權重越大,剛啟動統計資訊不足會採用輪詢,當統計資訊足夠,會切換到WeightedResponseTimeRuleRetryRule——按照輪詢演算法獲取伺服器列表,若獲取服務失敗,在指定的時間重試,獲取可用的服務BestAvailableRule——先過濾由於多次訪問故障而處於斷路器跳閘狀態的伺服器,然後選擇併發量最小的服務ZoneAvoidanceRule——預設規則,複合判斷server所在區域的效能和server可用性選擇伺服器,一般為RoundRobinRule

框架提供了這七種演算法,以下改用隨機演算法

@Configurationpublic class MyConfig {    @Bean    // 開啟LB (負載均衡)    @LoadBalanced    public RestTemplate getRestTemplate(){        return new RestTemplate();    }    @Bean    // 修改負載演算法策略為隨機演算法    public IRule getIRule(){        return new RandomRule();    }}

現在測試會發現,服務提供者的呼叫是隨機的,而非輪詢。

3、Ribbon自定義規則演算法:

規則:每個服務呼叫五次後輪詢

新建rules包和其兩個類,注意,MyRibbonRule類不能放在主啟動類所在的包及其子包下,不能被@componentScan所掃描 ,否則,此規則會適配所有的Ribbon客戶端,達不到特殊化要求

自定義規則FiveRoundRibbonRule.class,複製一份框架上提供的IRule例項類的原始碼進行修改,重點是其中的choose方法。

public class FiveRoundRibbonRule extends AbstractLoadBalancerRule {    private AtomicInteger nextServerCyclicCounter;    private static final boolean AVAILABLE_ONLY_SERVERS = true;    private static final boolean ALL_SERVERS = false;    private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);    private static int count = 0;  //被呼叫次數    private static int index = 0;  //當前微服務索引    public FiveRoundRibbonRule() {        this.nextServerCyclicCounter = new AtomicInteger(0);    }    public FiveRoundRibbonRule(ILoadBalancer lb) {        this();        this.setLoadBalancer(lb);    }    public Server choose(ILoadBalancer lb, Object key) {        if (lb == null) {            log.warn("no load balancer");            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 (count < 5) {               //呼叫次數小於5的時候,繼續呼叫當前服務                server = upList.get(index);                count++;            } else {              //呼叫次數大於5的時候,次數歸零,服務索引加1                count = 0;                index ++ ;                //當前服務索引達到最大時歸零                if (index >= upList.size() ) {                    index = 0;                }            }             if(server == null) {                Thread.yield();                continue;            }        }        return server;    }    public Server choose(Object key) {        return this.choose(this.getLoadBalancer(), key);    }    public void initWithNiwsConfig(IClientConfig clientConfig) {    }}

自定義規則的配置,MyRibbonRule.class

// 自定義Ribbon規則配置// 注意,此類不能放在主啟動類所在的包及其子包下,不能被@componentScan所掃描// 否則,此規則會適配所有的Ribbon客戶端,達不到特殊化要求@Configurationpublic class MyRibbonRule {    @Bean    // 修改負載演算法策略為隨機    public IRule getIRule(){        return new FiveRoundRibbonRule();        //return new RandomRule(); //此處也可以使用框架中的規則    }}

在啟動類中開啟自定義規則

@Configurationpublic class MyConfig {    @Bean    // 開啟LB (負載均衡)    @LoadBalanced    public RestTemplate getRestTemplate(){        return new RestTemplate();    }    @Bean    // 修改負載演算法策略為隨機演算法    public IRule getIRule(){        return new RandomRule();    }}

現在測試會發現,8001和8002服務會在呼叫五次後輪詢。

五、Fegin負載均衡

透過上面的Ribbon客戶端負載均衡,我們是是透過RestTemplate來呼叫微服務的,如果restTemplate.getForObject(REST_URL_PRE + "/user/{id}", Person.class,id);這句會呼叫多次,我們每次都需要重複寫出,這樣做達不到設計模式所需要的開閉原則。

我們可以將對微服務提供者的呼叫邏輯提取出來,形成介面的方式,消費端呼叫的時候注入這個介面例項,再進行方法的呼叫。面向介面程式設計才是正道。

由於此介面可能會被多個消費服務呼叫,因此我們將它放到公共服務模組中。

使用Fegin負載均衡。

1、microservice-cloud-api公共模組中增fegin的maven座標

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-openfeign</artifactId>    <version>2.2.6.RELEASE</version></dependency>

2、api公共模組中增PersonClientService介面

//fegin客戶端,value為被呼叫微服務的名稱@FeignClient(value = "MIRCROSERVICE-CLOUD-PROVIDER")public interface PersonClientService {    @GetMapping("user/list")    public List<Person> list();     @GetMapping("user/{id}")    public Person getById(@PathVariable int id);     @GetMapping("user/{name}/{age}")    public int insert(@PathVariable String name,@PathVariable int age);     @GetMapping("user/discovery")    public Object discovery();}

3、maven---clean---install

4、新建microservice-cloud-consummer-feign消費模組

5、pom中不需要再引入fegin座標,因為此pom中已經引入了api模組,而api中又引入了fegin座標

6、application.properties

server.port=81 #消費方不註冊自己,但是會獲取服務eureka.client.register-with-eureka=false #預設獲取服務eureka.client.fetch-registry=true #eureka服務地址eureka.client.service-url.defaultZone=http://www.woodlum7001.icu:7001/eureka/,http://www.woodlum.icu7002:7002/eureka/

7、控制類改寫

@RestControllerpublic class ConsummerController {    //像平常那樣注入PersonClientService介面的例項,透過介面來呼叫微服務    @Autowired    private PersonClientService personClientService;     @GetMapping("/list")    public List<Person> list() {        return personClientService.list();    }    @GetMapping("/{id}")    public Person getById(@PathVariable int id){        return personClientService.getById(id);    }    @GetMapping("/add/{name}/{age}")    public int insert(@PathVariable("name") String name,@PathVariable("age") String age){        Person person = new Person(name, Integer.parseInt(age));        return personClientService.insert(person.getName(),person.getAge());    }    @GetMapping("/discovery")    public Object discovery(){        return personClientService.discovery();    }}

8、啟動類修改

啟用feign,basePackages指定api模組中@FeignClient註解所在的當前包,此處踩坑一天

@SpringBootApplication@EnableEurekaClient//啟用feign,basePackages指定api模組中@FeignClient註解所在的當前包,此處踩坑一天@EnableFeignClients(basePackages = {"icu.woodlum.cn.service"})public class ConsummerFeign {    public static void main(String[] args) {        SpringApplication.run(ConsummerFeign.class, args);    }}

9、依次啟動微服務並測試

另外,服務提供的呼叫預設為輪詢方式

六、服務熔斷和服務降級Hystrix

在分散式系統中,當一個微服務發生異常時,或者因此網路原因很大機率會發生一個微服務不可用時,如果一個微服務此時有大量請求進來,就會發生請求阻塞,微服務中的呼叫異常可能會導致整個系統崩潰或者系統資源耗盡,這時我們就需要對異常或者不可用的服務進行隔離,以阻止對其他應用的影響。

1、服務熔斷

服務熔斷針對的是當前服務發生異常時,如何快速失敗,將異常的服務隔離開並快速返回一個失敗的訊息,防止異常的蔓延。

新建microservice-cloud-provider-8003-hystrix微服務

pom檔案增加Hystrix座標

<dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>     <version>2.2.6.RELEASE</version></dependency>

修改控制器類和服務例項

@GetMapping("/{id}")// 當發生異常時,呼叫fallbackMethod方法@HystrixCommand(fallbackMethod = "getHystrixCommand")public Person getById(@PathVariable int id){    return personService.getPersonById(id);}//Hystrix熔斷時呼叫的方法public Person getHystrixCommand(@PathVariable int id) {    return new Person().setId(id).setName("id:" + id + "不存在");}  //PersonServiceImpl類中丟擲一個異常,如果不存在當前查詢id的資料時異常public Person getPersonById(int id) {    Person person = personDao.selectById(id);    if (person == null) {        throw new RuntimeException("id:" + id + "不存在於資料庫中");    }    return person;}

啟用Hystrix

#fegin客戶端啟用hystrixfeign.hystrix.enabled=true

測試,id100時資料庫中不存在,程式碼丟擲異常,服務熔斷,快速熔斷並呼叫設定好的方法。

2、服務降級

服務降級針對的是當前服務不可用時,如何快速返回訊息,而不是一直等待。

服務降級一般使用除了網路故障導致的服務不可能用外,另外還有當某個微服務實時需求系統資源較多,這時我們就可以將不重要的少用的微服務停掉,讓更多的資源去處理緊急服務,這時一個請求如果在停掉的服務上時我們如何快速去響應訊息。

在服務熔斷中,熔斷方法耦合在控制器中,耦合性太強,由於控制器中呼叫了PersonClientService介面,因此我們可以在這個介面上來操作。

1、在api公共模組中新建服務失敗工廠類

public class FiveRoundRibbonRule extends AbstractLoadBalancerRule {    private AtomicInteger nextServerCyclicCounter;    private static final boolean AVAILABLE_ONLY_SERVERS = true;    private static final boolean ALL_SERVERS = false;    private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);    private static int count = 0;  //被呼叫次數    private static int index = 0;  //當前微服務索引    public FiveRoundRibbonRule() {        this.nextServerCyclicCounter = new AtomicInteger(0);    }    public FiveRoundRibbonRule(ILoadBalancer lb) {        this();        this.setLoadBalancer(lb);    }    public Server choose(ILoadBalancer lb, Object key) {        if (lb == null) {            log.warn("no load balancer");            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 (count < 5) {               //呼叫次數小於5的時候,繼續呼叫當前服務                server = upList.get(index);                count++;            } else {              //呼叫次數大於5的時候,次數歸零,服務索引加1                count = 0;                index ++ ;                //當前服務索引達到最大時歸零                if (index >= upList.size() ) {                    index = 0;                }            }             if(server == null) {                Thread.yield();                continue;            }        }        return server;    }    public Server choose(Object key) {        return this.choose(this.getLoadBalancer(), key);    }    public void initWithNiwsConfig(IClientConfig clientConfig) {    }}

2、修改PersonClientService介面

// 自定義Ribbon規則配置// 注意,此類不能放在主啟動類所在的包及其子包下,不能被@componentScan所掃描// 否則,此規則會適配所有的Ribbon客戶端,達不到特殊化要求@Configurationpublic class MyRibbonRule {    @Bean    // 修改負載演算法策略為隨機    public IRule getIRule(){        return new FiveRoundRibbonRule();        //return new RandomRule(); //此處也可以使用框架中的規則    }}

3、測試--服務熔斷

4、關閉Hystrix8003微服務,此時再進行測試,此時也就是我們所說的服務降級

5、當服務熔斷和服務降級模式都啟動的時候,會先進行服務熔斷嘗試,如果服務不可用才會進行服務降級,因此上面的例子在服務正常時會先進行@HystrixCommand註解處的異常方法判斷。

3、DashBoard服務監控

DashBoard(9001)針對的是Hystrix服務(8003)的監控,因此Hystrix服務提供者(8003)需要在方法上新增@HystrixCommand註解來啟動異常的服務熔斷。

1、建立DashBoard服務監控微服務microservice-cloud-consummer-hystrixdashboard9001

pom檔案

@SpringBootApplication@EnableEurekaClient// 自定義Ribbon規則,針對某一個微服務使用自定義規則@RibbonClient(name = "MIRCROSERVICE-CLOUD-PROVIDER",configuration = MyRibbonRule.class)public class Consummer {    public static void main(String[] args) {        SpringApplication.run(Consummer.class, args);    }}

application.properties檔案

server.port=9001#需要設定監控目標允許的主機名稱,多主機名以,分隔hystrix.dashboard.proxy-stream-allow-list = 127.0.0.1,localhost

2、改寫Hystrix8003服務提供者

@GetMapping("/{id}")// 當發生異常時,呼叫fallbackMethod方法@HystrixCommand(fallbackMethod = "getHystrixCommand")public Person getById(@PathVariable int id){   return personService.getPersonById(id);}  //Hystrix熔斷時呼叫的方法  public Person getHystrixCommand(@PathVariable int id) {    return new Person().setId(id).setName("id:" + id + "資料庫中不存在");}

pom檔案中需要有actuator座標

<dependency>   <groupId>org.springframework.boot</groupId>   <artifactId>spring-boot-starter-actuator</artifactId>   <version>2.3.5.RELEASE</version></dependency>

需要將/hystrix.stream暴露出來

依次啟動Eurekia、Hystrix8003、HystrixBoard9001服務。

http ://localhost:9001/hystrix,如果看到下面介面,表示監控服務啟動成功。

http ://localhost:8003/hystrix.stream,被監控微服務的ping,先要呼叫一下http ://localhost:8003/user/1帶@HystricCommand註解的介面,不然ping會一直空白

將http ://localhost:8003/hystrix.stream填入http ://localhost:9001/hystrix網頁中。

一直重新整理監控api的呼叫

當監控api呼叫發生錯誤時

監控儀表盤指標,左邊實心圓的大小代表的是流量,顏色代表的是被監控微服務的健康度,綠色>黃色>橙色>紅色。

七、zuul閘道器服務

閘道器主要是路由功能和過濾,和微服務系統構成一個反向代理,對外隱藏微服務的真實名稱及地址,同時方便外部訪問微服務,而不需要知道微服務的名稱及地址。

1、新建microservice-cloud-zuul-9000模組2、pom檔案

首先,zuul要向Eureka註冊並獲取微服務,因此Eureka依賴必須;然後zuul的座標,zuul中包含了web,actuator、hystrix、ribbon等依賴

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <parent>        <artifactId>microservice-cloud</artifactId>        <groupId>icu.woodlum.cn</groupId>        <version>0.0.1-SNAPSHOT</version>    </parent>    <modelVersion>4.0.0</modelVersion>    <artifactId>microservice-cloud-zuul-9000</artifactId>    <dependencies>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>            <version>2.2.6.RELEASE</version>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>            <version>2.2.6.RELEASE</version>        </dependency>    </dependencies> </project>
3、application.properties檔案
server.port= 9000 eureka.client.service-url.defaultZone= http://www.woodlum7001.icu:7001/eureka/,http://www.woodlum.icu7002:7002/eureka/eureka.client.instance.instance-id= zuulgataway.9000eureka.client.instance.prefer-ip-address= true spring.application.name= zuulgataway9000 #http://192.168.0.100:9000/actuator/info頁面資訊設定info.provider.name = microservice-cloud-zuul-9000info.company.name = icu.woodlum.cn#獲取pom中節點資訊,注意,父pom中build中雖然定界符設定為$,但是要使用@才能正常讀取#可能是新版本問題,當前工程actuator為2.3.4info.build.artifactId = @[email protected] = @project.modelVersion@
4、啟動類
@SpringBootApplication//開啟zuul代理@EnableZuulProxypublic class ZuulProxy9000 {    public static void main(String[] args) {        SpringApplication.run(ZuulProxy9000.class, args);    }}
5、測試

分別啟動Eureka叢集和服務提供者,再啟動zuul服務

但是其中被呼叫微服務的名稱在url中,這樣做不到隱藏

6、改進不對外暴露微服務的名稱

application.properties中增加

#微服務對映路徑修改,之前為http://localhost:9000/mircroservice-cloud-provider/**#對映後為http://localhost:9000/provider1/**,#目的是在API中對外不暴露微服務名稱#provider1設定分組,可以針對多個微服務分別修改對映路徑 zuul.routes.provider1.serviceId= mircroservice-cloud-providerzuul.routes.provider1.path= /provider1/** #zuul.routes.provider2.serviceId= mircroservice-cloud-provider2#zuul.routes.provider2.path= /provider12/**

但是之前透過微服務名稱來訪問url還是可以訪問的,這時我們需要透過忽略微服務的名稱來控制不暴露

application.properties中增加

#忽略對映之前的原路徑,單個用具體微服務名稱,多個用,分隔,或者*全部zuul.ignored-services= mircroservice-cloud-provider

這時http ://localhost:9000/mircroservice-cloud-provider/user/list就不能訪問了

擴充知識點:設定統一公共字首

#設定統一公共字首zuul.prefix = /woodlum
八、config配置中心

當微服務專案越來越多的時候,每一個微服務都有自己的配置檔案,在微服務執行期間如果要修改配置內容,需要一個一個修改,然後重新打包執行,這樣會很麻煩。

因此就有了配置中心,將配置提取出來使用一個外部的集中配置來作為配置檔案,程式執行中自動從配置中心獲取配置檔案進行載入,實現了配置檔案的動態化。

springcloud配置中心分為服務端和客戶端。

1、配置中心服務端

springcloud配置檔案預設採用git儲存方式,服務端是一個獨立的微服務,主要使用是連線客戶端和配置檔案所在伺服器的一箇中轉服務。

a、github建立配置倉庫b、新增config配置微服務3344

pom檔案

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-config-server</artifactId>    <version>2.2.6.RELEASE</version></dependency>

啟動類

@SpringBootApplication//開啟配置伺服器@EnableConfigServerpublic class ConfigServer3344 {    public static void main(String[] args) {        SpringApplication.run(ConfigServer3344.class,args);    }}

application.properties

server.port= 3344#當前微服務名稱spring.application.name= microservicecloud-configserver#git倉庫地址spring.cloud.config.server.git.uri= https://github.com/woodlum2017/spring-cloud-config-demo
2、改進Eureka註冊微服務7003、服務提供者8004和服務消費者82

建立三個properties屬性檔案,儲存為utf-8格式,其中內容為原本各自的屬性配置,將其push到github

三個微服務的application.properties檔案刪除,各自新建bootstrap.properties檔案,要spring中,bootstrap屬於系統級的配置,而application屬於使用者級的配置,系統級配置會優先載入

#eureka的bootstrapt.properties  #需要從github上讀取的資源名稱,注意沒有properties字尾名spring.cloud.config.name=springcloud-config-eureka-config#讀取的分支名spring.cloud.config.label=master#本微服務啟動後先去找3344號服務,透過SpringCloudConfig獲取Gitlub的服務地址spring.cloud.config.uri=http://www.woodlum3344.icu:3344  #provider的bootstrapt.properties #需要從github上讀取的資源名稱,注意沒有properties字尾名spring.cloud.config.name=springcloud-config-provider-config#讀取的分支名spring.cloud.config.label=master#本微服務啟動後先去找3344號服務,透過SpringCloudConfig獲取Gitlub的服務地址spring.cloud.config.uri=http://www.woodlum3344.icu:3344 #comsummer的bootstrapt.properties #需要從github上讀取的資源名稱,注意沒有properties字尾名spring.cloud.config.name=springcloud-config-consummer#讀取的分支名spring.cloud.config.label=master#本微服務啟動後先去找3344號服務,透過SpringCloudConfig獲取Gitlub的服務地址spring.cloud.config.uri=http://www.woodlum3344.icu:3344

啟動微服務

測試

12
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • java格式化之美