Spring Cloud1

Spring Cloud

代碼地址:https://github.com/jedyang/springCloud

springcloud中文社區(qū)給的定義是微服務(wù)架構(gòu)集大成者,云計算最佳業(yè)務(wù)實(shí)踐。
我的理解是分布式服務(wù)全家桶。
如果你有dubbo或其他分布式框架的使用經(jīng)驗(yàn),那么對springcloud提供的特性是很好理解的。
springcloud提供了如下特性:

  • 分布式配置
  • 服務(wù)注冊和發(fā)現(xiàn)
  • 路由
  • 遠(yuǎn)程服務(wù)調(diào)用
  • 負(fù)載均衡
  • 斷路器
  • 全局鎖
  • 主從選舉和集群狀態(tài)
  • 分布式消息

主要項(xiàng)目

spring cloud config

springcloud的配置管理項(xiàng)目,使用git管理??筛鶕?jù)不同環(huán)境管理不同參數(shù)。也可用于非spring應(yīng)用。

Spring Cloud Netflix

Spring Cloud包含了非常多的子框架,其中,Spring Cloud Netflix是其中一套框架,由Netflix開發(fā)后來又并入Spring Cloud大家庭,它主要提供的模塊包括:服務(wù)發(fā)現(xiàn)(Eureka),斷路器(Hystrix),智能路由(Zuul)和客戶端負(fù)載平衡(Ribbon)。

Spring Cloud Bus

事件總線。使用分布式消息將服務(wù)和服務(wù)實(shí)例聯(lián)系起來。在集群的狀態(tài)變化傳播中作用很大。

Spring Cloud for Cloud Foundry

讓你的應(yīng)用同Cloudfoundry進(jìn)行整合。(Cloudfoundry是最近很熱的開源PaaS云平臺)。讓你很容易實(shí)現(xiàn)SSO(單點(diǎn)登錄)、OAuth2(一個關(guān)于授權(quán)的開放網(wǎng)絡(luò)標(biāo)準(zhǔn))功能,以及Cloudfoundry的服務(wù)分發(fā)器。

Spring Cloud Cloud Foundry Service Broker

提供了一個擴(kuò)展點(diǎn),以便于開發(fā)基于 Cloud Foundry管理的服務(wù)分發(fā)器。

Spring Cloud Cluster

主從選舉?;趜ookeeper,redis,hazelcast(hazelcast是一個開放源碼集群和高度可擴(kuò)展的數(shù)據(jù)分發(fā)平臺),consul(支持多數(shù)據(jù)中心下,分布式高可用的,服務(wù)發(fā)現(xiàn)和配置共享)的抽象和實(shí)現(xiàn)。

Spring Cloud Consul

基于Consul實(shí)現(xiàn)的服務(wù)發(fā)現(xiàn)和配置管理

Spring Cloud Security

提供了對OAuth2 負(fù)載均衡的客戶端,以及基于Zuul代理的頭部校驗(yàn)。

Spring Cloud Sleuth

對spring cloud分布式應(yīng)用的服務(wù)鏈路追蹤

Spring Cloud Data Flow

一個建立數(shù)據(jù)集成和實(shí)時處理管道的工具集。
簡化了應(yīng)用程序的開發(fā)和部署 將精力集中到數(shù)據(jù)處理的用例上。

Spring Cloud Stream

一個輕量級的事件驅(qū)動的微服務(wù)框架。可以快速構(gòu)建應(yīng)用和外部系統(tǒng)對接??梢栽趕pringboot應(yīng)用之間通過簡單的聲明模型,基于kafka或rabbitMq交互消息。

Spring Cloud Stream App Starters

一個基于springboot的同外部系統(tǒng)的集成應(yīng)用

Spring Cloud Task

短時任務(wù)處理框架。如定時任務(wù)。

Spring Cloud Task App Starters

對應(yīng)的具體應(yīng)用。

Spring Cloud for Amazon Web Services

方便同AWS服務(wù)集成

Spring Cloud Connectors

使各種PaaS平臺應(yīng)用連接基礎(chǔ)后端服務(wù)(如數(shù)據(jù)庫服務(wù)、消息中間件)更容易。

Spring Cloud Starters

用于使基于springcloud的依賴管理更方便

Spring Cloud CLI

是一個插件,可以用groovy語言快速創(chuàng)建spring cloud應(yīng)用

Spring Cloud Contract

是一個消費(fèi)者驅(qū)動的、面向Java的契約框架。

Spring Cloud Netflix

Netflix是spring cloud的核心框架,必學(xué)必用。

微服務(wù)架構(gòu)

首先,我們來看看一般的微服務(wù)架構(gòu)需要的功能或使用場景:

  1. 我們把整個系統(tǒng)根據(jù)業(yè)務(wù)拆分成幾個子系統(tǒng)。

  2. 每個子系統(tǒng)可以部署多個應(yīng)用,多個應(yīng)用之間使用負(fù)載均衡。

  3. 需要一個服務(wù)注冊中心,所有的服務(wù)都在注冊中心注冊,負(fù)載均衡也是通過在注冊中心注冊的服務(wù)來使用一定策略來實(shí)現(xiàn)。

  4. 所有的客戶端都通過同一個網(wǎng)關(guān)地址訪問后臺的服務(wù),通過路由配置,網(wǎng)關(guān)來判斷一個URL請求由哪個服務(wù)處理。請求轉(zhuǎn)發(fā)到服務(wù)上的時候也使用負(fù)載均衡。

  5. 服務(wù)之間有時候也需要相互訪問。例如有一個用戶模塊,其他服務(wù)在處理一些業(yè)務(wù)的時候,要獲取用戶服務(wù)的用戶數(shù)據(jù)。

  6. 需要一個斷路器,及時處理服務(wù)調(diào)用時的超時和錯誤,防止由于其中一個服務(wù)的問題而導(dǎo)致整體系統(tǒng)的癱瘓。

  7. 還需要一個監(jiān)控功能,監(jiān)控每個服務(wù)調(diào)用花費(fèi)的時間等。

Netflix

Spring Cloud Netflix框架剛好就滿足了上面所有的需求,而且最重要的是,使用起來非常的簡單。Spring Cloud Netflix包含的組件及其主要功能大致如下:

  1. Eureka,服務(wù)注冊和發(fā)現(xiàn),它提供了一個服務(wù)注冊中心、服務(wù)發(fā)現(xiàn)的客戶端,還有一個方便的查看所有注冊的服務(wù)的界面。 所有的服務(wù)使用Eureka的服務(wù)發(fā)現(xiàn)客戶端來將自己注冊到Eureka的服務(wù)器上。

  2. Zuul,網(wǎng)關(guān),所有的客戶端請求通過這個網(wǎng)關(guān)訪問后臺的服務(wù)。他可以使用一定的路由配置來判斷某一個URL由哪個服務(wù)來處理。并從Eureka獲取注冊的服務(wù)來轉(zhuǎn)發(fā)請求。

  3. Ribbon,即負(fù)載均衡,Zuul網(wǎng)關(guān)將一個請求發(fā)送給某一個服務(wù)的應(yīng)用的時候,如果一個服務(wù)啟動了多個實(shí)例,就會通過Ribbon來通過一定的負(fù)載均衡策略來發(fā)送給某一個服務(wù)實(shí)例。

  4. Feign,服務(wù)客戶端,服務(wù)之間如果需要相互訪問,可以使用RestTemplate,也可以使用Feign客戶端訪問。它默認(rèn)會使用Ribbon來實(shí)現(xiàn)負(fù)載均衡。

  5. Hystrix,監(jiān)控和斷路器。我們只需要在服務(wù)接口上添加Hystrix標(biāo)簽,就可以實(shí)現(xiàn)對這個接口的監(jiān)控和斷路器功能。

  6. Hystrix Dashboard,監(jiān)控面板,他提供了一個界面,可以監(jiān)控各個服務(wù)上的服務(wù)調(diào)用所消耗的時間等。

  7. Turbine,監(jiān)控聚合,使用Hystrix監(jiān)控,我們需要打開每一個服務(wù)實(shí)例的監(jiān)控信息來查看。而Turbine可以幫助我們把所有的服務(wù)實(shí)例的監(jiān)控信息聚合到一個地方統(tǒng)一查看。這樣就不需要挨個打開一個個的頁面一個個查看。

接下來一個一個看。

Eureka

作為服務(wù)注冊與發(fā)現(xiàn)的中心。我們的demo分為兩部分,一個server,一個client。 這里的server是指注冊中心。client是指向注冊中心注冊或者訂閱服務(wù)的消費(fèi)者。

  1. 創(chuàng)建一個maven主工程

  2. 建一個server模塊。
    右鍵-->new module -->Spring Initializr -->next
    -->填寫相關(guān)信息-->next
    -->dependencies 選Cloud Discovery-->Eureka Server
    -->finish

  3. 第一個server

     // 服務(wù)注冊中心注解
     @EnableEurekaServer
     @SpringBootApplication
     public class ServerApplication {
     
         public static void main(String[] args) {
             SpringApplication.run(ServerApplication.class, args);
         }
     }
    

    代碼非常簡單,就是在原來springboot的啟動類上加了一個注解。
    @EnableEurekaServer
    將該實(shí)例注冊為一個Eureka的server角色。

  4. 配置文件
    在resources下建一個appication.yml
    配置如下:
    server:
    port: 8761

     eureka:
       instance:
         hostname: localhost
       client:
         registerWithEureka: false
         fetchRegistry: false
         serviceUrl:
           defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    

(注意,yml對于格式要求非常嚴(yán)格,縮進(jìn)不要搞錯)

  1. 啟動工程
    訪問http://localhost:8761。可以看到注冊中心的界面。
    此時還沒有服務(wù)提供者注冊過來。
1.png
  1. 同創(chuàng)建server一樣的步驟,建一個client

  2. 代碼如下

     @SpringBootApplication
     @EnableEurekaClient
     @RestController
     public class ClientApplication {
     
         @Value("${server.port}")
         String port;
         @RequestMapping("/hi")
         public String home(@RequestParam String name) {
             return "hi "+name+",i am from port:" +port;
         }
     
         public static void main(String[] args) {
             SpringApplication.run(ClientApplication.class, args);
         }
     }
    

    @EnableEurekaClient表明這是一個client

  3. 配置文件

     eureka:
       client:
         serviceUrl:
           defaultZone: http://localhost:8761/eureka/
     server:
       port: 8762
     spring:
       application:
         name: service-hi
    
  4. 啟動工程
    查看http://localhost:8761已經(jīng)注冊進(jìn)來

2.png

配置文件中spring.application.name指定的name就是注冊的服務(wù)名。
其他應(yīng)用調(diào)用也是根據(jù)這個name來找。

ribbon+restTemplate

微服務(wù)架構(gòu)中,業(yè)務(wù)被拆分成單獨(dú)的服務(wù),服務(wù)之間通過rest相互調(diào)用。在springcloud中有兩種調(diào)用方式:ribbon+restTemplate和feign。
ribbon是一個負(fù)載均衡客戶端,可以很好的控制http和tcp之上的行為,feign也是使用ribbon的。

  1. 再啟動一個進(jìn)程
    為了嘗試負(fù)載均衡,基于上面的工程。改一下client的配置端口,將8762改為8763再啟動一個服務(wù)提供方client。
    tips:idea默認(rèn)run 是單實(shí)例的,所以再次run main會讓你停掉之前的服務(wù)。其實(shí)在run configration中配置一下,把Single instance only選項(xiàng)勾掉就可以了。

  2. 查看注冊中心
    測試應(yīng)該看到

3.png

已經(jīng)有兩個服務(wù)注冊進(jìn)來了。

  1. 建一個服務(wù)消費(fèi)者
    新建一個springboot工程:service-consumer
    在dependency時勾選web、ribbon、eureka discovery

  2. 在resources下新建application.yml
    配置:

     eureka:
       client:
         serviceUrl:
           defaultZone: http://localhost:8761/eureka/
     server:
       port: 8764
     spring:
       application:
         name: service-consumer
    
  3. 修改啟動類

     @SpringBootApplication
     @EnableDiscoveryClient
     public class ServicveConsumerApplication {
     
         public static void main(String[] args) {
             SpringApplication.run(ServicveConsumerApplication.class, args);
         }
     
         @Bean
         @LoadBalanced
         RestTemplate restTemplate() {
             return new RestTemplate();
         }
     }
    

    注解@EnableDiscoveryClient作用是向注冊中心注冊自己為消費(fèi)者。

    @LoadBalanced表明開啟負(fù)載均衡功能。
    @Bean注解聲明一個RestTemplate bean

  4. 建一個服務(wù)類

         @Service
     public class HelloService {
     
         @Autowired
         RestTemplate restTemplate;
     
         public String sayHello(String name) {
             return restTemplate.getForObject("http://SERVICE-HI/hi?name=" + name, String.class);
         }
     }
    
  5. 建一個對應(yīng)的測試用例

     @RunWith(SpringRunner.class)
     @SpringBootTest(classes=ServicveConsumerApplication.class)
     public class HelloServiceTest {
     
         @Autowired
         HelloService helloService;
     
         @Test
         public void sayHello() throws Exception {
             for (int i = 0; i < 10; i++){
                 System.out.println(helloService.sayHello("yunsheng"));
             }
     
         }
     
     }
    

跑十次看一下結(jié)果。

    hi yunsheng,i am from port:8763
    hi yunsheng,i am from port:8762
    hi yunsheng,i am from port:8763
    hi yunsheng,i am from port:8762
    hi yunsheng,i am from port:8763
    hi yunsheng,i am from port:8762
    hi yunsheng,i am from port:8763
    hi yunsheng,i am from port:8762
    hi yunsheng,i am from port:8763
    hi yunsheng,i am from port:8762

很明顯看到了負(fù)載均衡的效果。

當(dāng)前我們的應(yīng)用架構(gòu)是:

4.png

feign

Feign是一個聲明試的web服務(wù)客戶端??梢宰屇銓憌eb service client更簡單。Feign默認(rèn)集成了Ribbon。
還是使用上面的工程,知識需要加一個Feign的依賴。

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
    </dependency>
  1. 新建一個啟動類

     @SpringBootApplication
     @EnableDiscoveryClient
     @EnableFeignClients
     public class FeignConsumerApplication {
     
         public static void main(String[] args) {
             SpringApplication.run(FeignConsumerApplication.class, args);
         }
     
     }
    

    新增一個@EnableFeignClients注解開啟Feign功能

  2. 新建一個feign服務(wù)類

     @FeignClient(value = "service-hi")
     public interface FeignConsumeService {
     
         @RequestMapping(value = "/hi",method = RequestMethod.GET)
         String sayHiFromClientOne(@RequestParam(value = "name") String name);
     }
    

這里的功能就是一個服務(wù)代理的接口,只是內(nèi)部默認(rèn)實(shí)現(xiàn)了負(fù)載均衡。
這里的requestMapping必須是服務(wù)提供者的RequestMapping保持一致。

  1. controller層對外暴露一個服務(wù)調(diào)用

     @RestController
     public class HiController {
         @Autowired
         FeignConsumeService feignConsumeService;
     
         @RequestMapping(value = "/feignHi", method = RequestMethod.GET)
         public String sayHi(@RequestParam(value = "name") String name){
             return feignConsumeService.sayHiFromFeign(name);
         }
     
     
     }
    

這里的requestMapping隨便寫。

  1. 啟動。
5.png
可以看到消費(fèi)者已經(jīng)注冊。  
  1. 消費(fèi)
    因?yàn)槲覀冮_放的是rest服務(wù),所以直接瀏覽器測試。
    瀏覽器多次訪問
    http://localhost:8764/feignHi?name=yunsheng
    可以看到負(fù)載均衡的效果,間隔調(diào)用8762和8763的服務(wù)。

Hystrix斷路器

在微服務(wù)架構(gòu)中,各個服務(wù)模塊獨(dú)立部署。但是由于各種原因,并不能保證服務(wù)100%成功。如果某個服務(wù)發(fā)送異常,產(chǎn)生線程阻塞。測試有大量請求進(jìn)入,會導(dǎo)致servlet線程被耗盡。由于服務(wù)之間的依賴,導(dǎo)致耽擱服務(wù)的異常被傳播擴(kuò)大,產(chǎn)生災(zāi)難性后果。為了避免這種情況,業(yè)界采用斷路器模式,當(dāng)服務(wù)不可用情況達(dá)到一定閾值后,斷路器打開,避免故障傳播。

  1. 添加依賴
    基于service-consumer工程添加依賴

     <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-hystrix</artifactId>
     </dependency>
    
  2. 改造啟動類

     @SpringBootApplication
     @EnableDiscoveryClient
     @EnableHystrix
     public class ServicveConsumerApplication {
     
         public static void main(String[] args) {
             SpringApplication.run(ServicveConsumerApplication.class, args);
         }
     
         @Bean
         @LoadBalanced
         RestTemplate restTemplate() {
             return new RestTemplate();
         }
     }
    

    添加@EnableHystrix注解,開啟斷路器功能

  3. 改造HelloService

     @Service
     public class HelloService {
     
         @Autowired
         RestTemplate restTemplate;
     
         @HystrixCommand(fallbackMethod = "sayErr")
         public String sayHello(String name) {
             return restTemplate.getForObject("http://SERVICE-HI/hi?name=" + name, String.class);
         }
     
         public String sayErr(String name) {
             return "hi,"+name+",sorry,error!";
         }
     }
    

給之前的sayHello方法添加@HystrixCommand注解,并指定失敗時調(diào)用的方法。

  1. 測試
    先將8762和8763兩個服務(wù)提供者關(guān)掉。
    先將 @HystrixCommand(fallbackMethod = "sayErr")注釋掉,關(guān)閉斷路器。
    為了方便看出效果。也給ribbon方式新建一個rest的controller。

     @RestController
     public class HiController {
         @Autowired
         HelloService helloService;
     
         @RequestMapping(value = "/ribbonHi", method = RequestMethod.GET)
         public String sayHi(@RequestParam(value = "name") String name) {
             return helloService.sayHello("yys");
         }
     
     
     }
    

瀏覽器訪問http://localhost:8764/ribbonHi?name=yys
需要等到響應(yīng)超時才能得到錯誤頁面。
但是開啟了斷路器之后,
再次嘗試,可以看到很快輸出hi,yys,sorry,error!。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容