服務的註冊與發現Eureka(二)

一、服務治理概念

在傳統rpc遠程調用中,服務與服務依賴關係,管理比較複雜,因此須要使用服務治理,管理服務與服務之間依賴關係,能夠實現服務調用、負載均衡、容錯等,實現服務發現與註冊。java

二、服務的註冊與發現概念

 在服務註冊與發現中,有一個註冊中心,當服務器啓動的時候,會把當前本身服務器的信息 好比 服務地址通信地址等以別名方式註冊到註冊中心上。mysql

 另外一方(消費者|服務提供者),以該別名的方式去註冊中心上獲取到實際的服務通信地址,讓後在實現本地rpc調用遠程。web

服務註冊與發下原理圖:算法

三、什麼Eureka

Netflix在設計Euraka時遵照的就是AP原則spring

 

四、Eureka的基本架構

 

Eureka包含兩個組件:Eureka Server和Eureka Clientsql

Eureka Server提供服務數據庫

各節點啓動服務後,會在EurekaServer中進行註冊,這樣EurekaServer中的服務註冊表中apache

將會存儲到全部可用服務節點的信息,服務節點信息能夠在界面中直觀的看到api

Eureka Client是一個java客戶端,用於簡化Eureka Server的交互,客戶端同時也具有一個內置的,使用輪詢(round-robin)負載算法的負載均衡器.在應用啓動後,將會向Eureka Server發送心跳(默認週期爲30s).緩存

若是Eureka Server在多個心跳週期內沒有接收到某個節點的心跳,EurekaServer將會從服務註冊表中把這個服務節點移除(默認90s)

 五、Eureka 三大角色

Eureka Server提供服務註冊和發現

Service Provider服務提供方將自身服務註冊到Eureka,從而是服務消費方可以找到

Service Consumer服務消費方從Eureka獲取註冊服務列表,從而可以消費服務

 六、服務提供者與消費關係

服務提供者:提供服務被人調用

消費者:調用被人服務

   一、服務消費者模式

       獲取服務

       消費者啓動的時候,使用服務別名,會發送一個rest請求到服務註冊中心獲取對應的服務信息,讓後會緩存到本地jvm客戶端中,同時客戶端每隔30秒從服務器上更新一次。

能夠經過 fetch-inte vall-seconds=30參數進行修以經過eureka.client .registry該參數默認值爲30, 單位爲秒。

      服務下線

      在系統運行過程當中必然會面臨關閉或重啓服務的某個實例的狀況,在服務關閉期有咱們天然不但願客戶端會繼續調用關閉了的實例。因此在客戶端程序中,當服務實例過正常的關閉操做時,它會觸發一個服務下線的REST請求給Eureka Server, 告訴服務日中心:「我要下線了」。服務端在接收到請求以後,將該服務狀態置爲下線(DOWN),井該下線事件傳播出去。

二、服務註冊模式

失效剔除

      有些時候,咱們的服務實例並不必定會正常下線,可能因爲內存溢出、網絡故障氣因使得服務不能正常工做,而服務註冊中心並未收到「服務下線」的請求。爲了從服務表中將這些沒法提供服務的實例剔除,Eureka Server 在啓動的時候會建立一個定時任多默認每隔一一段時間(默認爲60秒)將當前清單中超時(默認爲90秒)沒有續約的服務除出去

 自我保護

      當咱們在本地調試基於Eureka的程序時,基本上都會碰到這樣-一個問題, 在服務主中心的信息面板中出現相似下面的紅色警告信息( )

      EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY 'RERENENALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIREDTO BE SAFE.

實際上,該警告就是觸發了Eureka Server的自我保護機制。以前咱們介紹過,服務註冊到Eureka Server以後,會維護個心跳鏈接, 告訴Eureka Server本身還活 着。Eureka Server在運行期間,會統計心跳失敗的比例在15分鐘以內是否低於85%若是出現低於的狀況單機調試的時候很容易知足,實際在生產環境上一般是因爲網絡不穩定致使),EuServer會將當前的實例註冊信息保護起來,讓這些實例不會過時,儘量保護這些註冊信-息。可是,在這段保護期間內實例若出現問題,那麼客戶端很容易拿到實際已經不存服務實例,會出現調用失敗的狀況,因此客戶端必需要有容錯機制,好比可使用請使用重試、斷路器等機制。

因爲本地調試很容易觸發註冊中心的保護機制,這會使得註冊中心維護的服務實仍那麼準確。因此,咱們在本地進行開發的時候,可使用eureka . server . enablself preservation=false參數來關閉保護機制,以確保註冊中心能夠將不可用的例正確剔除。

 後面搭建註冊中心的時候加入這個配置就能夠關閉自我保護

eureka: server: # 測試時關閉自我保護機制,保證不可用服務及時踢出 enable-self-preservation: false eviction-interval-timer-in-ms: 2000

七、盤點下目前的工做狀況

總父工程

通用模塊api

服務提供者Provider

服務消費者Consumer

 八、微服務構建案例工程模塊

   構建步驟

      一、microservicecloud總體父工程Project

       新建父工程microservicecloud,切記爲Packaging是pom模式,主要是定義pom文件,將後續各個子模塊公用的jar包等統一提出來,相似一個抽象的父類

    pom文件:

 <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> <log4j.version>1.2.17</log4j.version> <lombok.version>1.16.18</lombok.version> <springcloud-version>Finchley.SR1</springcloud-version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${springcloud-version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.6.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.0.4</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.31</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> </dependencies> </dependencyManagement>

二、microservicecloud-api公共子模塊Module

新建microservicecloud-api

 

建立完成後請回到父工程查看pom文件變化以下圖所示:

pom文件

<dependencies><!-- 當前Module須要用到的jar包,按本身需求添加,若是父類已經包含了,能夠不用寫版本號 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>

新建部門Entity且配合lombok使用

@AllArgsConstructor//全參數構造 @NoArgsConstructor//無參數構造器 @Data//get set 方法 @Accessors(chain = true)//鏈式風格 public class Dept implements Serializable { private Long deptno; // 主鍵 private String dname; // 部門名稱 private String db_source;// 來自那個數據庫,由於微服務架構能夠一個服務對應一個數據庫,同一個信息被存儲到不一樣數據庫  }

mvn clean install 後給其餘模塊引用,達到通用的目的,也即須要用到部門實體的話,不用每一個都定義一份直接引用本模塊便可

 三、microservicecloud-provider-dept-8001部門微服務提供者Module

新建一個microservicecloud-provider-dept-8001,建立完成後請回到父工程查看pom文件變化以下圖所示:

 

pom文件

<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- 引入本身定義的api通用包,可使用Dept部門Entity --> <dependency> <groupId>com.yehui</groupId> <artifactId>microservicecloud-api</artifactId> <version>${project.version}</version> <scope>compile</scope> </dependency> </dependencies>

application.yml文件

server: port: 8001 mybatis: config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路徑 type-aliases-package: com.yehui.entity # 全部Entity別名類所在包 mapper-locations: classpath:mybatis/mapper/**/*.xml # mapper映射文件 spring: application: name: microservicecloud-dept //服務註冊名稱 datasource: type: com.alibaba.druid.pool.DruidDataSource # 當前數據源操做類型 driver-class-name: org.gjt.mm.mysql.Driver # mysql驅動包 url: jdbc:mysql://localhost:3306/clouddb01 # 數據庫名稱 username: root password: root dbcp2: min-idle: 5 # 數據庫鏈接池的最小維持鏈接數 initial-size: 5 # 初始化鏈接數 max-total: 5 # 最大鏈接數 max-wait-millis: 200 # 等待鏈接獲取的最大超時時間

工程src/main/resources目錄下新建mybatis文件夾後新建mybatis.cfg.xml文件

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="cacheEnabled" value="true"/><!-- 二級緩存開啓 --> </settings> </configuration>

mysql建立部門sql腳本

DROP TABLE IF EXISTS `dept`; CREATE TABLE `dept` ( `deptno` BIGINT(20) NOT NULL DEFAULT 0, `dname` VARCHAR(60) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `db_source` VARCHAR(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ) ENGINE = INNODB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT; INSERT INTO `dept` VALUES (1, '開發部', 'clouddb01'); INSERT INTO `dept` VALUES (2, '人事部', 'clouddb01'); INSERT INTO `dept` VALUES (3, '財務部', 'clouddb01'); INSERT INTO `dept` VALUES (4, '市場部', 'clouddb01'); INSERT INTO `dept` VALUES (5, '運維部', 'clouddb01');

DeptMapper部門接口

@Mapper public interface DeptMapper { public boolean addDept(Dept dept); public Dept findById(Long id); public List<Dept> findAll(); }

工程src/main/resources/mybatis目錄下新建mapper文件夾後在創建DeptMapper.xml

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.yehui.mapper.DeptMapper"> <select id="findById" resultType="Dept" parameterType="Long"> select deptno,dname,db_source from dept where deptno=#{deptno}; </select> <select id="findAll" resultType="Dept"> select deptno,dname,db_source from dept; </select> <insert id="addDept" parameterType="Dept"> INSERT INTO dept(dname,db_source) VALUES(#{dname},DATABASE()); </insert> </mapper>

DeptService部門服務接口

public interface DeptService { public boolean addDept(Dept dept); public Dept findById(Long id); public List<Dept> findAll(); }

DeptServiceImpl部門服務接口實現類

@Service public class DeptServiceImpl implements DeptService { @Autowired private DeptMapper deptMapper; @Override public boolean addDept(Dept dept) { return deptMapper.addDept(dept); } @Override public Dept findById(Long id) { return deptMapper.findById(id); } @Override public List<Dept> findAll() { return deptMapper.findAll(); } }

DeptController部門微服務提供者REST

@RestController @RequestMapping("/dept") public class DeptController { @Autowired private DeptService deptService; @RequestMapping(value = "/addDept") public boolean addDept(Dept dept) { return deptService.addDept(dept); } @RequestMapping("/findById/{id}") public Dept findById(@PathVariable("id") Long id) { return deptService.findById(id); } @RequestMapping("/findAll") public List<Dept> findAll() { return deptService.findAll(); } }

主啓動類

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

測試

訪問地址:http://localhost:8001/dept/findAll

效果以下:

四、microservicecloud-consumer-dept-80部門微服務消費者Module

新建一個microservicecloud-provider-dept-80,建立完成後請回到父工程查看pom文件變化以下圖所示:

pom文件

<dependencies> <!-- 引入本身定義的api通用包,可使用Dept部門Entity --> <dependency> <groupId>com.yehui</groupId> <artifactId>microservicecloud-api</artifactId> <version>${project.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>

 yml文件

server: port: 80

com.yehui.config包下ConfigBean編寫(相似spring裏面的applicationContext.xml寫入的注入Bean)

@Configuration public class ConfigBean { @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } }

com.yehui.controller包下新建DeptController部門微服務消費者REST

@RestController public class DeptController { private static String REST_URL_PREFIX = "http://localhost:8001"; /** RestTemplate 提供了多種便捷訪問遠程Http服務的方法,是一種簡單便捷的訪問restful服務模板類,是spring提供的用於訪問Rest服務的客戶端模板工具集 * 使用 使用restTemplate訪問restful接口很是的簡單粗暴無腦。 (url, requestMap, * ResponseBean.class)這三個參數分別表明 REST請求地址、請求參數、HTTP響應轉換被轉換成的對象類型。 */ @Autowired private RestTemplate restTemplate; @RequestMapping(value = "/consumer/dept/add") public boolean add(Dept dept) { return restTemplate.postForObject(REST_URL_PREFIX + "/dept/addDept", dept, Boolean.class); } @RequestMapping("/findAll") public List<Dept> findAll() { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/findAll",List.class); } }

ConSumeAppStart主啓動類

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

測試訪問http://localhost:80/findAll

效果:

五、註冊中心環境搭建

pom文件

 <dependencies> <!--eureka-server服務端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies>

 application.yml

server: port: 7001 ###eureka 基本信息配置 eureka: instance: ###註冊到eurekaip地址 hostname: localhost #eureka服務端的實例名稱 client: service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #單機 設置與Eureka Server交互的地址查詢服務和註冊服務都須要依賴這個地址(單機)。  ###由於本身是爲註冊中心,不須要本身註冊本身 register-with-eureka: false #表示不像註冊中心註冊本身 ###由於本身是爲註冊中心,不須要檢索服務 fetch-registry: false #false表示本身端就是註冊中心,個人職責就是維護服務實例,並不須要去檢索服務

 主啓動類

@SpringBootApplication @EnableEurekaServer // EurekaServer服務器端啓動類,接受其它微服務註冊進來
public class SpringCloudService7001_APP { public static void main(String[] args) { SpringApplication.run(SpringCloudService7001_APP.class); } }

測試:http://localhost:7001/

若是所示:

五、註冊服務提供者

microservicecloud-provider-dept-8001將已有的部門將微服務註冊到eureka服務中心

修改microservicecloud-provider-dept-8001

pom文件添加相關依賴

 <!-- 將微服務provider側註冊進eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>

yml添加

eureka: client: #客戶端註冊進eureka服務列表內 service-url: defaultZone: http://localhost:7001/eureka/  ###由於該應用爲註冊中心,不會註冊本身 register-with-eureka: true ###是否須要從eureka上獲取註冊信息 fetch-registry: true

主啓動類添加新註解

@SpringBootApplication @EnableEurekaClient//本服務啓動後會自動註冊進eureka服務中 public class ProviderAppStart8001 { public static void main(String[] args) { SpringApplication.run(ProviderAppStart8001.class); } }

效果以下:訪問路徑http://localhost:7001/

六、主機映射名稱修改

hosts 文件裏面映射這樣127.0.0.1  eureka7001.com

修改microservicecloud-eureka-7001工程的yml文件

server: port: 7001 eureka: client: fetch-registry: false service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ register-with-eureka: false instance: hostname: eureka7001.com #實例的名稱

修改microservicecloud-provider-dept-8001 yml文件

server: port: 8001 mybatis: config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路徑 type-aliases-package: com.yehui.entity # 全部Entity別名類所在包 mapper-locations: classpath:mybatis/mapper/**/*.xml # mapper映射文件 #應用名稱 spring: application: name: microservicecloud-dept datasource: type: com.alibaba.druid.pool.DruidDataSource # 當前數據源操做類型 driver-class-name: org.gjt.mm.mysql.Driver # mysql驅動包 url: jdbc:mysql://localhost:3306/clouddb01 # 數據庫名稱 username: root password: root dbcp2: min-idle: 5 # 數據庫鏈接池的最小維持鏈接數 initial-size: 5 # 初始化鏈接數 max-total: 5 # 最大鏈接數 max-wait-millis: 200 # 等待鏈接獲取的最大超時時間 eureka: client: #客戶端註冊進eureka服務列表內 service-url: defaultZone: http://localhost:7001/eureka/ ###是否向註冊中心註冊本身 register-with-eureka: true ###是否須要從eureka上獲取註冊信息 fetch-registry: true

修改microservicecloud-eureka-7001yml文件 修改添加

server: port: 7001 eureka: client: fetch-registry: false service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ register-with-eureka: false instance: hostname: eureka7001.com #實例的名稱

效果訪問路徑:http://eureka7001.com:7001/

七、完善_主機IP信息提示

在父類pom文件添加以下配置

<build> <!--父工程的項目名稱--> <finalName>microservicecloud</finalName> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <configuration> <!--以$開頭結尾 符合在src/main/resources路徑下面訪問到 主要是yml文件或者properties文件--> <delimiters> <delimit>$</delimit> </delimiters> </configuration> </plugin> </plugins> </build>

microservicecloud-provider-dept-8001 pom文件添加依賴

<!-- actuator監控信息完善 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>

在microservicecloud-provider-dept-8001 yml文件添加以下:

八、使用rest方式調用服務

修改microservicecloud-consumer-dept-80

pom文件添加依賴

 <!-- 將微服務provider側註冊進eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>

yml文件添加配置

###服務註冊到eureka地址 eureka: client: service-url: defaultZone: http://localhost:7001/eureka/ #向服務中心註冊本身  ###是否向服務中心註冊本身 register-with-eureka: true ###是否須要從eureka上獲取註冊信息 fetch-registry: true #服務的名稱 spring: application: name: ConsomeApp

config配置類添加註解

@Configuration public class ConfigBean { @Bean @LoadBalanced //註解代表這個restRemplate開啓負載均衡的功能。 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }

controller類修改

@RestController public class DeptController { private static String REST_URL_PREFIX="http://MICROSERVICECLOUD-DEPT";//引用的名稱 /** RestTemplate 提供了多種便捷訪問遠程Http服務的方法,是一種簡單便捷的訪問restful服務模板類,是spring提供的用於訪問Rest服務的客戶端模板工具集 * 使用 使用restTemplate訪問restful接口很是的簡單粗暴無腦。 (url, requestMap, * ResponseBean.class)這三個參數分別表明 REST請求地址、請求參數、HTTP響應轉換被轉換成的對象類型。 */ @Autowired private RestTemplate restTemplate; @RequestMapping(value = "/consumer/dept/add") public boolean add(Dept dept) { return restTemplate.postForObject(REST_URL_PREFIX + "/dept/addDept", dept, Boolean.class); } @RequestMapping("/findAll") public List<Dept> findAll() { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/findAll",List.class); } }

啓動類新增註解

@SpringBootApplication @EnableEurekaClient //代表本身是一個eurekaclient. public class ConSumeAppStart { public static void main(String[] args) { SpringApplication.run(ConSumeAppStart.class); } }

 測試訪問;http://localhost/findAll

相關文章
相關標籤/搜索