微服務起源:微服務html
微服務將單一應用程序劃分爲一組小服務,每一個服務獨立在及本身的進程中,經過Restful方式互相溝通、調用。每一個服務提供單個業務功能,去耦合。java
微服務:指系統中的一個服務應用。ios
微服務架構:架構風格,即包括微服務及微服務之間的通訊。git
微服務 | 技術 |
---|---|
開發 | 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 |
廠商 | 技術選用 |
---|---|
阿里 | 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微服務架構,涵蓋了服務註冊/發現、配置中心、全鏈路監控、服務網管、負載均衡、熔斷器等,使用SpringBooot簡化開發,提供快速構建分佈式系統的工具,包括配置管理、服務發現、斷路器、路由、微代理、事件總線、全局鎖、決策精選、分佈式會話等,均可以使用SpringBoot開發進行快速啓動和部署。github
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
建立父工程Maven配置打包類型爲Pom數據庫
在父工程中建立子工程模塊bootstrap
建立子工程後端
服務註冊與發現,註冊訂閱後能夠依據服務標識符訪問服務,不須要修改配置文件,功能和Zookeeper相似,遵循AP原則。
功能對比 | Eurka | Zookeeper |
---|---|---|
架構 | CS架構 Server端註冊服務器 | RPC |
穩定性 | 冗餘備份,全部集羣都可獨立工做 | 主從備份,選舉費時 |
服務端:提供服務註冊服務,存儲全部可用服務節點的信息。
客戶端: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); }
客戶端負載均衡工具
<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(); }
RoundRobinRule
輪詢
RandomRule
隨機
AvaliabilityFilteringRule
過濾訪問致使故障處於斷路器跳閘的服務、超併發閾值服務,剩餘輪詢
WeightedResponseTimeRule
根據平均響應時間分配權重,權重大的被選中概率大,服務啓動使用輪詢,後切換爲WeightedResponseTimeRule。
RetryRule
按照輪詢獲取服務,失敗時,在指定時間內重試。
BestAvaliableRule
過濾故障跳閘服務,選擇併發量小的服務。
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 } }
聲明式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); }
@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保證在服務出現爲題時,不會致使總體服務失敗,避免級聯故障,提升分佈式系統的彈性。當某個服務出現故障,通關斷路器的故障監控,向調用方法返回一個符合預期的、可處理的備選響應,而不是進行等待或拋出異常,保證調用線程不會長時間等待、返回無用信息,避免故障蔓延。
<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); } }
@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; } }; } }
服務監控,持續記錄經過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>
路由功能,對外部請求進行轉發,即外部訪問與服務的路由網關,提供過濾、路由功能,將以一個服務註冊到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:
針對當出現大量的微服務時,提供一個配置中心,對微服務的配置進行集中管理。
在github中建立一個庫並保存地址
提交文件
server: port: 3344 spring: application: name: microservicecloud-config cloud: config: server: git: uri: *:*.git #GitHub上面的git倉庫名字
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>