SpringCloud

SpringCloud

入門問題

  1. 微服務概念
  2. 微服務之間如何通訊
  3. SpringCloud與Dubbo的區別
  4. SpringBoot與SpringCloud的關係
  5. 服務熔斷和服務降級概念
  6. 微服務的優缺點
  7. 微服務技術棧
  8. eureka和zookeeper的區別

微服務概述

微服務起源:微服務html

微服務將單一應用程序劃分爲一組小服務,每一個服務獨立在及本身的進程中,經過Restful方式互相溝通、調用。每一個服務提供單個業務功能,去耦合。java


微服務與微服務架構

微服務:指系統中的一個服務應用。ios

微服務架構:架構風格,即包括微服務及微服務之間的通訊。git


微服務的優缺點

優勢

  1. 服務高內聚,完成一個細微化的業務或功能
  2. 單個服務的開發更便捷,開發簡單、開發效率高
  3. 微服務可由獨立團隊開發
  4. 鬆耦合,開發及部署都獨立
  5. 能夠由不一樣語言開發,易於集成
  6. 先後端分離、靈活分配數據庫

缺點

  1. 分佈式系統的複雜性
  2. 運維難度增長,系統部署依賴問題
  3. 服務間通訊額外花費
  4. 數據一致性、系統集成測試難度
  5. 性能監控難

微服務技術棧

微服務 技術
開發 Spring、SpringBoot、SpringMVC
配置管理 Archaius(Netflix)、Diamond(Ali)
註冊與實現 Eureka、Consul、Zookeeper
調用 Rest、RPC、gRPC
熔斷器 Hystrix、Envoy
負載均衡 Ribbon、Nginx
接口調用工具 Feign
消息隊列 Kaflka、RabbitMQ、ActiveMQ
配置中心管理 SpringCloudConfig、Chef
路由(API網關) Zuul
監控 Zabbix、Nagios、Metrics、Spectator
全鏈路追蹤 ZipKin、Brave、Dapper
部署 Docker、OpenStack、Kubernates
數據流操做 SpringCloud Steam(Redis、Rabbit...)
事件消息總線 Spring Cloud Bus

SpringCloud 架構

主流選用

廠商 技術選用
阿里 Dubbo/HSF
京東 JSF
新浪微博 Motan
噹噹 Dubbo

框架對比

功能 Spring Cloud Motan gRPC Thrift Dubbo/DubboX
定位 完整微服務 RPC+ZK/Consul RPC RPC RPC
Rest 支持
RPC
多語言
註冊/發現 (Eurka) Zookeeper/Consul
負載均衡 Zuul+Ribbon
配置服務 Archaius/sp config servier
調用鏈監控 Zuul API
高可用/容錯 Hystrix Ribbon
其餘

SpringCloud簡介

微服務

SpringCloud微服務架構,涵蓋了服務註冊/發現、配置中心、全鏈路監控、服務網管、負載均衡、熔斷器等,使用SpringBooot簡化開發,提供快速構建分佈式系統的工具,包括配置管理、服務發現、斷路器、路由、微代理、事件總線、全局鎖、決策精選、分佈式會話等,均可以使用SpringBoot開發進行快速啓動和部署。github

SpringCloud:一站式分佈式微服務解決方案算法


Dubbo 對比 SpringCloud

對比 Dubbo SpringCloud
註冊中心 Zookeeper Eureka
調用方式 RPC REST API
監控 Dubbo-minitor spring boot admin
斷路器 不完善 SC Netfilx Hystrix
網管 SC Netfilx Zull
分佈式配置 SC config
跟蹤 SC Sleuth
消息總線 SC Bus
數據流 SC Stream
批量任務 SC Task
...

文檔

官方文檔 API 文檔 中國社區 Spring中文網spring


實戰

版本

  1. Cloud: Dalston.SR1
  2. Boot: 1.5.9

建立工程

建立父工程Maven配置打包類型爲Pom數據庫

在父工程中建立子工程模塊bootstrap

建立子工程後端


Eureka

Eurka

服務註冊與發現,註冊訂閱後能夠依據服務標識符訪問服務,不須要修改配置文件,功能和Zookeeper相似,遵循AP原則。

功能對比 Eurka Zookeeper
架構 CS架構 Server端註冊服務器 RPC
穩定性 冗餘備份,全部集羣都可獨立工做 主從備份,選舉費時

Eureka簡介

服務端:提供服務註冊服務,存儲全部可用服務節點的信息。

客戶端:Java客戶端,簡化同服務端的交互,包含負載均衡器,啓動後會向服務端週期發送心跳(默認30s),當服務器在多個週期中未受到某節點心跳(默認90s),節點將會移除。

註冊中心

server:
  port: 7001

eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false   #不註冊自身
    fetch-registry: false         #服務端
    service-url:
      defalutZone: http://${eureka.instance.hostname}:${s
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer7001_App {
    public static void main(String[] args) {

        SpringApplication.run(EurekaServer7001_App.class,args);
    }
}

服務提供者

eureka:
  client: #客戶端註冊進eureka服務列表內
    service-url:
      defaultZone: http://localhost:7001/eureka
      #defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: microservicecloud-dept-8001
    prefer-ip-address: true     #訪問路徑能夠顯示IP地址
@EnableEurekaClient
@SpringBootApplication
public class DeptProvider8001_App {

    public static void main(String[] args) {
        SpringApplication.run(DeptProvider8001_App.class,args);
    }
}

服務消費者

server:
  port: 80
@Configuration
public class ConfigBean
{ 
    @Bean
    @LoadBalanced//Spring Cloud Ribbon 負載均衡的工具。
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}
private static final String REST_URL_PREFIX = "http://localhost:8001";

//private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/consumer/dept/add")
    public boolean add(Dept dept)
    {
        return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
    }

    @RequestMapping(value = "/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id)
    {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
    }

    @SuppressWarnings("unchecked")
    @RequestMapping(value = "/consumer/dept/list")
    public List<Dept> list()
    {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
    }

    // 測試@EnableDiscoveryClient,消費端能夠調用服務發現
    @RequestMapping(value = "/consumer/dept/discovery")
    public Object discovery()
    {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/discovery", Object.class);
    }

負載均衡

Ribbon

客戶端負載均衡工具

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
@Configuration
public class ConfigBean
{ 
    @Bean
    @LoadBalanced//Spring Cloud Ribbon 負載均衡的工具。
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}
@Bean
    public IRule myRule()
    {
        //return new RoundRobinRule();
        //return new RandomRule();//達到的目的,用咱們從新選擇的隨機算法替代默認的輪詢。
        return new RetryRule();
    }

算法

  1. RoundRobinRule

    輪詢

  2. RandomRule

    隨機

  3. AvaliabilityFilteringRule

    過濾訪問致使故障處於斷路器跳閘的服務、超併發閾值服務,剩餘輪詢

  4. WeightedResponseTimeRule

    根據平均響應時間分配權重,權重大的被選中概率大,服務啓動使用輪詢,後切換爲WeightedResponseTimeRule。

  5. RetryRule

    按照輪詢獲取服務,失敗時,在指定時間內重試。

  6. BestAvaliableRule

    過濾故障跳閘服務,選擇併發量小的服務。

  7. ZoneAvoidanceRule

    默認規則,複合判斷服務性能和選擇可用服務。

自定義負載均衡策略

import com.wang.myrule.MySelfRule;
/////////////////
@RibbonClient(name="microservicecloud-dept",configration=MySelfRule.class)
/////////////////
@EnableEurekaClient
@SpringBootApplication
public class ConsumerDept80 {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerDept80.class,args);
    }
}
//自動配置類 不能載SpringBoot的自動掃描範圍
//若是被掃描 全部的客戶端將共享這個配置
package com.wang.myrule;//與主配置並列包

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;

@Configuration
public class MySelfRule
{
    @Bean
    public IRule myRule()
    {
        //return new RandomRule();
        //return new RoundRobinRule();
        return new RandomRule();// 本身編寫的類
    }
}

自定義規則編寫

自定義策略類

package com.atguigu.myrule;

import java.util.List;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

public class RandomRuleUserDefined extends AbstractLoadBalancerRule
{

    // total = 0 // 當total==5之後,咱們指針才能往下走,
    // index = 0 // 當前對外提供服務的服務器地址,
    // total須要從新置爲零,可是已經達到過一個5次,咱們的index = 1
    // 分析:咱們5次,可是微服務只有8001 8002 8003 三臺,OK?
    // 
    
    
    private int total = 0;          // 總共被調用的次數,目前要求每臺被調用5次
    private int currentIndex = 0;   // 當前提供服務的機器號

    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) {
     /*
        * No servers. End regardless of pass, because subsequent passes only get more
      * restrictive.
      */
                return null;
            }

//          int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3);
//          server = upList.get(index);

            
//          private int total = 0;          // 總共被調用的次數,目前要求每臺被調用5次
//          private int currentIndex = 0;   // 當前提供服務的機器號
            if(total < 5)
            {
                server = upList.get(currentIndex);
                total++;
            }else {
                total = 0;
                currentIndex++;
                if(currentIndex >= upList.size())
                {
                  currentIndex = 0;
                }
            }           
            
            
            if (server == null) {
        /*
         * The only time this should happen is if the server list were somehow trimmed.
         * This is a transient condition. Retry after yielding.
       */
                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;

    }

    @Override
    public Server choose(Object key)
    {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig)
    {
        // TODO Auto-generated method stub

    }

}

策略類繼承關係

1536454563936

Feign

聲明式Rest客戶端,使得編寫Web服務客戶端更簡單,能夠與Eurek、Rebbon組合使用。

定義一個接口添加註解,便可使用。

Ribbon+RestTemplate:調用

接口+註解:調用

依賴

<dependency>
      <groupId>cn.springcloud.feign</groupId>
      <artifactId>venus-cloud-starter-feign</artifactId>
    </dependency>

接口+註解

//@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class) //熔斷器類

@FeignClient(value = "MICROSERVICECLOUD-DEPT")
public interface DeptClientService
{
    @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
    public Dept get(@PathVariable("id") long id);

    @RequestMapping(value = "/dept/list", method = RequestMethod.GET)
    public List<Dept> list();

    @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
    public boolean add(Dept dept);
}

Controller

@RestController
public class DeptController_Consumer
{
    @Autowired
    private DeptClientService service;

    @RequestMapping(value = "/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id)
    {
        return this.service.get(id);
    }

    @RequestMapping(value = "/consumer/dept/list")
    public List<Dept> list()
    {
        return this.service.list();
    }

    @RequestMapping(value = "/consumer/dept/add")
    public Object add(Dept dept)
    {
        return this.service.add(dept);
    }
}

集成了Rabbon,Ribbon+RestTemplate調用微服務 ==》接口+註解,調用接口的方式調用服務,便是在調用某個微服務的方式從使用RestTemplate的方式轉爲使用接口方式調用,Fegin仍是能夠使用Rabbon的負載均衡。


Hystrix

處理分佈式系統的延遲和容錯的開源庫,分佈式系統中,服務調用不可避免會有調用失敗、超時、異常出現,Hystrix保證在服務出現爲題時,不會致使總體服務失敗,避免級聯故障,提升分佈式系統的彈性。當某個服務出現故障,通關斷路器的故障監控,向調用方法返回一個符合預期的、可處理的備選響應,而不是進行等待或拋出異常,保證調用線程不會長時間等待、返回無用信息,避免故障蔓延。

使用方法

依賴

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>

啓用

@SpringBootApplication
@EnableEurekaClient 
@EnableDiscoveryClient 

@EnableCircuitBreaker       //對hystrix熔斷機制的支持
public class DeptProviderHystrix
{
    public static void main(String[] args)
    {
        SpringApplication.run(DeptProviderHystrixp.class, args);
    }
}

Controller

@RestController
public class DeptController
{
    @Autowired
    private DeptService service = null;
    //調用服務方法失敗並拋出了錯誤信息
  //自動調用@HystrixCommand標註好的fallbackMethod調用類中的指定方法
    @HystrixCommand(fallbackMethod = "processHystrix_Get")
  @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
    public Dept get(@PathVariable("id") Long id)
    {

        Dept dept = this.service.get(id);
        
        if (null == dept) {
            throw new RuntimeException("該ID:" + id + "沒有沒有對應的信息");
        }
        
        return dept;
    }

  //相似異常通知
    public Dept processHystrix_Get(@PathVariable("id") Long id)
    {
        return new Dept().setDeptno(id).setDname("該ID:" +id + "沒有沒有對應的信息,null--@HystrixCommand")
                .setDb_source("no this database in MySQL");
    }
}

熔斷機制,當微服務在某個服務處發生了超時、異常時,由Hystrix返回一個結果,結果符合調用服務者的要求。舉例實際使用,須要重寫FallbackFactory接口並在Feign註解中配置fallbackFactory,便可實現異常處理與業務模塊分離,解耦和。

服務降級

服務降級在客戶端完成,暫時關閉服務,爲其餘服務節省資源,當服務關閉後,Hystrix依舊會爲接口調用時返回一個信息。

//實現FallbackFactory接口
@Component 
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>
{
    @Override
    public DeptClientService create(Throwable throwable)
    {
        return new DeptClientService() {
            @Override
            public Dept get(long id)
            {
                return new Dept().setDeptno(id).setDname("該ID:" + id + "沒有沒有對應的信息")
                        .setDb_source("no this database in MySQL");
                        //,Consumer客戶端提供的降級信息,此刻服務Provider已經關閉
            }

            @Override
            public List<Dept> list()
            {
                return null;
            }

            @Override
            public boolean add(Dept dept)
            {
                return false;
            }
        };
    }
}

HystrixDashboard

服務監控,持續記錄經過Hystrix發起的請求的執行信息,並以統計報表和圖形的形式展示給用戶,即微服務的圖形化監控。

依賴

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
        </dependency>

主類

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

服務

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

監控指標

  1. Delay:輪詢監控信息的延遲事件,默認2000毫秒
  2. Title:監控標題

  1. 失敗
  2. 超時
  3. 成功
  4. 錯誤請求
  5. 拒絕
  6. 短路
  7. 錯誤

Zuul路由網關

路由功能,對外部請求進行轉發,即外部訪問與服務的路由網關,提供過濾、路由功能,將以一個服務註冊到Eureka中,同時實現網關功能,能夠配置其餘服務的路由訪問規則。

依賴

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>

配置

server: 
  port: 9527 //server_port
                     //服務將經過路由進行訪問
 
spring: 
  application:
    name: microservicecloud-zuul-gateway
 
eureka: 
  client: 
    service-url: 
      defaultZone: eureka-ip
  instance:
    instance-id: intance_id
    prefer-ip-address: true 
 
 
zuul: //服務地址映射定義
  #ignored-services: microservicecloud-dept //過濾服務地址訪問
  prefix: /prefix               //公共前綴
  ignored-services: "*" //過濾所有服務地址
  routes: 
    mydept.serviceId: microservicecloud-dept
    mydept.path: /myurl/**
 
 info:

分佈式配置中心

針對當出現大量的微服務時,提供一個配置中心,對微服務的配置進行集中管理。

服務端

  1. 在github中建立一個庫並保存地址

  2. 在本地建立庫並克隆建立的庫
  3. 建立文件配置文件application.yml(UTF-8)
  4. 提交文件

server: 
  port: 3344 
  
spring:
  application:
    name:  microservicecloud-config
  cloud:
    config:
      server:
        git:
          uri: *:*.git #GitHub上面的git倉庫名字

客戶端

bootstrap.xml
spring:
  cloud:
    config:
      name: microservicecloud-config-client #須要從github上讀取的資源名稱,
                                                                                #注意沒有yml後綴名
      profile: test   #本次訪問的配置項
      label: master   
      uri: ip/url:3344  #本微服務啓動後先去找3344號服務,
                                        #經過SpringCloudConfig獲取GitHub的服務地址
依賴
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

微服務框架圖

相關文章
相關標籤/搜索