1 Spring Cloud Eureka服務治理
註:此隨筆為讀書筆記。《Spring Cloud微服務實戰》
什麽是微服務?
微服務是將一個原本獨立的系統拆分成若幹個小型服務(一般按照功能模塊拆分),這些小型服務都在各自獨立的進程中運行,服務之間通過基於HTTP的RESTful API進行通信協作。每個微服務維護自身的數據存儲、業務開發、自動化測試案例以及獨立部署機制。維護自身的數據存儲稱為數據管理的去中心化。由於數據管理的去中心化,各個微服務的數據一致性成為一個難題,因此,需要強調的是各個服務之間進行無“事務”的調用。
微服務架構中針對不同應用場景和出現的各種問題出現了各種解決方案和開源框架。服務治理:阿裏的Dubbo、當當網擴展的Dubbox、Netflix的Eureka、Apache的Consul等;分布式配置管理:百度的Disconf、Spring cloud的Config、淘寶的Diamond等;批量任務:當當網的Elastic-Job、Spring Cloud的Task等;服務跟蹤:京東的Hydra、Spring Cloud的Sleuth等;等等。
Spring Cloud不只是解決微服務中的某一個問題,而是一個解決微服務架構實施的綜合性解決框架,它整合了諸多被廣泛實踐和證明過的框架作為實施的基礎部件,又在該體系基礎上創建了一些優秀的邊緣組件。如Spring Cloud Eureka、Spring Cloud Ribbon、Spring Cloud Hytrix、Spring Cloud Feign等針對微服務的解決方案。
Spring Cloud是一個基於Spring Boot實現的微服務框架,針對微服務應用的不同場景,產生了各種技術架構:
1.Spring Cloud Config:配置管理工具;
2.Spring Cloud Netflix:Spring Cloud的核心組件,對多個Netflix OSS開源套件進行整合;
a.Eureka:服務治理組件,包含服務註冊中心、服務註冊、服務發現和消費機制的實現;
b.Hystrix:容錯管理組件,實現斷路由器模式,幫助服務依賴中出現的延遲和故障提供強大的容錯能力;
c.Ribbon:客戶端負載均衡的服務調用組件;
d.Feign:基於Ribbon和Hystrix的聲明式服務調用組件,是對兩者的整合;
e.Zuul:網關組件,提供智能路由、訪問過濾等功能。
f.Archaius:外部化配置組件。
3.Spring Cloud Bus:事件、消息總線,用於傳播集群中的狀態變化或事件,以觸發後續的處理,比如用來動態刷新配置等;
4.Spring Cloud Cluster:針對Zookeeper、Redis、Hazelcast、Consul的選舉算法和通用狀態模式的實現;
5.Spring Cloud Stream:通過Redis、Rabbit和Kafka實現的消費服務,可以通過簡單的聲明式模型來發送和接收消息;
6.Spring Cloud Sleuth:Spring Cloud應用的分布式跟蹤實現,可以完美整合Zipkin;
7.Spring Cloud Zookeeper:基於Zookeeper的服務發現與配置管理組件。等等。
Spring Cloud Eureka主要負責微服務架構當中的微服務治裏工作,是微服務架構當中最為核心和基礎的模塊,用來實現各個微服務的服務註冊和服務發現。
Spring Cloud Eureka,使用Netflix Eureka來實現微服務的註冊和發現,包括服務端組件和客戶端組件,服務端和客戶端組件均有java語言編寫的,所以Eureka主要使用於java語言的分布式系統。但是,它也支持非java語言的微服務架構,只是,需要程序員自己來實現Eureka的客戶端程序。一些開放平臺上有一些客戶端框架,例如,.NET平臺的Steeltoe、Node.js的eureka-js-client等。這裏說的服務端就是註冊中心,客戶端就是一些微服務。
Eureka服務治理體系有三大核心角色:服務註冊中心、服務提供者以及服務消費者。服務註冊中心一般稱為Eureka服務端,服務提供者和服務消費者稱為Eureka客戶端。
本隨筆涉及的開發工具:IDEA,技術框架:Spring Boot和Spring Cloud
1.搭建服務註冊中心(單節點模式)
1.創建一個基礎的Spring Boot項目,命名:eureka-server,pom.xml內容
<?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"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>demo-eureka</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>pom.xml
2.Spring Boot啟動類中添加註解@EnableEurekaServer
package com.example.eurekaserver; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class Application { public static void main(String[] args) { new SpringApplicationBuilder(Application.class).web(true).run(args); } }Application.java
3.Spring Boot配置文件信息,裏面有兩點需要註意
server:
port: 1111
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false #1. false:代表不讓註冊中心註冊自己
fetch-registry: false #2. false:註冊中心職責是維護服務實例,不需要去檢索服務
serviceUrl:
default: http://${eureka.instance.hostname}:${server.port}/eureka/
采用yml文件,只需將application.properties文件後綴改成application.yml即可。
4.項目結構:
5.瀏覽器輸入http://localhost:1111/,即可看到Eureka信息面板。
2.註冊微服務(服務提供者)
提供服務的應用可以是Spring Boot應用,也可以是其他技術平臺且遵循Eureka通信機制的應用。將自己的應用註冊到註冊中心Eureka,以供其他應用使用。
1.創建一個Spring Boot項目,命名:demo-server,pom.xml文件內容
<?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"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>demo-server</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>pom.xml
2.測試Controller
@RestController public class HelloController { @Autowired private DiscoveryClient discoveryClient; @RequestMapping(value = "/hello", method = RequestMethod.GET) public String index() { ServiceInstance instance = discoveryClient.getLocalServiceInstance(); return "hello world! host:" + instance.getHost() + ", service_id" + instance.getServiceId(); } }HelloController.java
3.啟動類添加註解@EnableDiscoverClient
@EnableDiscoveryClient @SpringBootApplication public class DemoServerApplication { public static void main(String[] args) { SpringApplication.run(DemoServerApplication.class, args); } }
4.配置文件信息 application.yml
spring:
application:
name: demo-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/eureka/ #指定註冊中心
5.啟動項目,可以看到微服務已經註冊到註冊中心
3.服務發現和消費
服務消費者,會做兩件事,服務發現和服務消費,服務發現由Eureka的客戶端完成,服務消費由Ribbon完成。Ribbon是一個基於Http和Tcp的負載均衡器,它可以根據客戶端(一般指服務消費者)中配置的ribbonServerList服務列表以輪詢的方式訪問,以達到負載均衡的作用。
1.創建一個ribbon-consumer項目,pom.xml中添加 spring-cloud-starter-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"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>ribbon-consumer</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <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> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>pom.xml
2.啟動類
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @EnableDiscoveryClient @SpringBootApplication public class RibbonConsumerApplication { @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(RibbonConsumerApplication.class, args); } }RibbonConsumerApplication.java
3.controller
@RestController public class ConsumerController { @Autowired private RestTemplate restTemplate; @RequestMapping(value = "/ribbon-consumer", method = RequestMethod.GET) public String helloConsumer() { return restTemplate.getForEntity("http://DEMO-SERVICE/hello", String.class).getBody(); } }ConsumerController.java
4.配置文件
server:
port: 9001
spring:
application:
name: ribbon-consumer
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/eureka/
application.yml
4.測試
用不同端口啟動兩個demo-server服務,用來測試ribbon的負載均衡(在demo-server中的接口添加打印日誌,可以在控制臺看出那個服務被調用)
java -jar demo-0.0.1-SNAPSHOT.jar --server.port=8081
java -jar demo-0.0.1-SNAPSHOT.jar --server.port=8082
啟動ribbon-consumer項目
註冊中心
訪問http://localhost:9001/ribbon-consumer
4.高可用註冊(高可用模式)
兩個註冊服務互相註冊即可實現高可用。
1.在第一個搭建的服務註冊中心項目eureka-server上,將原來的application.yml註釋,新建兩個application-peer1.yml和application-peer2.yml
server:
port: 1111
spring:
profiles: peer1
eureka:
instance:
hostname: peer1
client:
serviceUrl:
defaultZone: http://peer2:1112/eureka/
application-peer1
server:
port: 1112
spring:
profiles: peer2
eureka:
instance:
hostname: peer2
client:
serviceUrl:
defaultZone: http://peer1:1111/eureka/
application-peer2
2.啟動項目即可
3.修改demo-server項目中的配置文件,添加信息如下
spring:
application:
name: demo-service
eureka:
client:
serviceUrl:
defaultZone: http://peer1:1111/eureka/,http://peer2:1112/eureka/
然後啟動該項目,即該服務皆註冊到兩個註冊中心。
此時,若其中一個註冊中心掛掉,那麽另外一個註冊中心可以繼續使用。
1 Spring Cloud Eureka服務治理