目錄
前言
服務治理
在傳統的RPC遠程調用框架中, 管理每個服務與服務之間依賴關係比較複雜,管理比較複雜,所以需要使用服務治理,管理服務與服務之間依賴關係,可以實現服務調用、負載均衡、容錯等,實現服務發現與註冊。
服務註冊與發現
首先在分佈式微服務系統中,有一個註冊中心,使用CS的設計架構,當服務端的微服務啓動時,會把自己當前服務的相關信息(服務名,服務所在主機地址等)註冊到註冊中心。而消費端的微服務會根據所需的服務端的微服務別名到註冊中心獲取實際的服務通訊地址,調用遠程服務(RPC:dubbo+zk或eureka)(DNS協議:k8s + coredns)。
註冊中心
配置總工程pom
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>top.hcode</groupId>
<artifactId>springcloud</artifactId>
<version>1.0-SNAPSHOT</version>
<!--打包方式 pom-->
<packaging>pom</packaging>
<properties>
<project.bulid.sourceEncoding>UTF-8</project.bulid.sourceEncoding>
<maven.compiler.sourse>1.8</maven.compiler.sourse>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<lombok.version>1.16.10</lombok.version>
<log4j.version>1.2.17</log4j.version>
<mysql.version>5.1.47</mysql.version>
<mybatis.spring.boot.version>2.1.1</mybatis.spring.boot.version>
</properties>
<dependencyManagement>
<dependencies>
<!--Springcloud的依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring cloud 阿里巴巴-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--Springboot依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--數據庫-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.version}</version>
</dependency>
<!--Springboot:啓動器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--log4j日誌-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<!--junit單元測試-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Eureka
Eureka包含兩個組件: Eureka Server和Eureka Client
- Eureka Server提供服務註冊服務
各個微服務節點通過配置啓動後,會在EurekaServer中進行註冊, 這樣EurekaServer中的服務註冊表中將 會存儲所有可用服務節點的信息,服務節點的信息可以在界面中直觀看到。
- EurekaClient通過註冊中心進行訪問
Java客戶端,用於簡化Eureka Server的交互,客戶端同時也具備一個內置的、 使用輪詢(round-robin)負載算法的負載均衡器。在應用啓動後,將會向Eureka Server發送心跳(默認週期爲30秒)。如果Eureka Server在多個心跳週期內沒有接收到某個節點的心跳,EurekaServer將 會從服務註冊表中把這個服務節點移除(默認90秒)
Eureka Server的搭建
每個子項目第一步:創建maven子模塊
- 配置該子模塊的pom.xml依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- 配置yml(單機)
注:eureka7001.com,eureka7002.com是本地配置127.0.0.1映射爲這些域名,主要是爲了區別,在服務器上可根據服務器更改
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服務端的實例名稱
client:
register-with-eureka: false #是否向eureka註冊中心註冊自己
fetch-registry: false #false表示自己爲註冊中心
service-url: #監控頁面
# 單機: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#集羣(關聯其它註冊中心) defaultZone: http://eureka7002.com:7002/,.....
defaultZone: http://eureka7002.com:7002/eureka/
server:
enable-self-preservation: true # eureka的自我保護模式開啓
eviction-interval-timer-in-ms: 30000 # 自我保護幾秒
配置yml(集羣):其它不變,修改註冊空間添加其它註冊中心地址
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/,.....
- 在主啓動類上添加開啓Eureka註冊中心的註解
@SpringBootApplication
@EnableEurekaServer //服務器啓動類,可以接受別人的註冊
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
Eureka Client的搭建
首先根據CS架構應該分爲微服務提供者(provider)和微服務消費者(consumer),同時兩者都得註冊到Eureka註冊中心,並且微服務提供者(服務端)可以進行集羣擴建,配置均是端口不同即可(當然,在不同服務器就沒這個限制,本地是爲了端口不被佔用)。
微服務提供端(服務端)
首先:同樣也是得先創建子模塊maven項目(Springboot也行,偷懶就不用手動創建啓動類~)
注:不做實際業務的演示,只說明配置,集羣的話相同配置,修改端口號即可(本地僞集羣)
- 配置該模塊的pom.xml依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</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-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
- 配置applaction.yml(直接集羣版,單機版也就是註冊空間只有一個的區別)
server:
port: 8001
spring:
application:
name: springcloud-provider-test #服務名
#eureka的配置,註冊到註冊中心
eureka:
client:
service-url:
defaultZone: http://eureka7002.com:7002/eureka/, http://eureka7001.com:7001/eureka/
# 集羣必須爲true
fetch-registry: true
instance:
instance-id: springcloud-provider-test-8001 #修改eureka上的監控的默認信息
prefer-ip-address: true #顯示eureka界面的服務ip
lease-renewal-interval-in-seconds: 30 # 向eureka註冊中心發送心跳的時間間隔
lease-expiration-duration-in-seconds: 90 # eureka註冊中心收到最後一次心跳等待的時間上限,超過就清除該服務
- 配置主啓動類的註解
//啓動類
@SpringBootApplication
@EnableEurekaClient //註冊到註冊中心
@EnableDiscoveryClient //服務發現
public class TestProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(TestProvider_8001.class, args);
}
}
微服務消費端(客戶端)
- 在pom.xml導入依賴
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</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-actuator</artifactId>
</dependency>
- 配置application.yml(集羣)
server:
port: 80
eureka:
client:
register-with-eureka: false #不註冊自己
service-url:
#到哪些註冊中心發現服務
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/
- 啓動類
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
服務調用
一般客戶訪問都是走消費端(consumer)的請求,然後消費端(consumer)要到註冊中心根據客戶請求URL路徑所對應的controller層所指定的微服務,根據別名請求調用服務端(provider)的微服務執行相應請求(這裏默認的負載均衡策略爲輪詢),返回結果到消費端,消費端再將結果封裝返回到前端客戶訪問的頁面。
消費端調用方式有兩種:Ribbon和feign。
(一) Ribbon方式:
- 不用再導入依賴,spring-cloud-starter-netflix-eureka-client中已經包含了ribbon,當然要自己導入也行。
在consumer的maven工程的pom.xml加入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<dependency/>
- 加個配置類,將RestTemplate注入到spring容器中
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced //設置實現負載均衡,Ribbon
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
//修改負載均衡的策略,這次選擇已有的隨機訪問,下面不寫的話,默認爲輪詢
//AvailabilityFilteringRule : 先過濾掉出現故障的服務器,對剩下的服務進行輪詢
//RoundRobinRule 輪詢 默認設置
//RandomRule 隨機
//WeightedResponseTimeRule 權重
//RetryRule:先按照輪詢獲取,若獲取服務失敗,則在指定時間內進行重試
@Bean
public IRule myRule(){
return new RandomRule();
}
}
- 在controller層進行請求服務端的操作
服務名對應provider端所配置的服務名
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
//Ribbon,地址應該是個變量,通過服務名來訪問
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-TEST";
@RequestMapping("/consumer/test")
public String test() {
return restTemplate.getForObject(REST_URL_PREFIX+"/test" String.class);
}
}
- 相對應的,在服務端的controller裏面得有個相對應的路徑請求方法
@RestController
public class ProviderController {
@RequestMapping("/test")
public String test() {
return "(●'◡'●),調用服務成功哦~";
}
}
(二)feign方式(接口):
- 在consumer端導入依賴
Netflix的feign已經不更新了,所以這次用的組件時springcloud的openfeign
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
- 在啓動類上開啓feign的註解
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
- 在service層創建一個接口,新增註解@FeignClient,方法(參數)需同服務端controller層的路徑請求方法一樣。
@FeignClient(value = "springcloud-provider-test") //value填的就是provider端的服務別名
@Component //交給spring容器託管
public interface TestService {
@RequestMapping("/test")
public String test();
}
- 然後呢,在controller層測試(還是consumer端的哦)
@RestController
public class DeptConsumerController {
@Autowired
private TestService testService ;
@RequestMapping("/consumer/test")
public String test(){
return testService.test();
}
}
Zookeeper
先到官網下載安裝zookeeper
- 下載zookeeper :https://zookeeper.apache.org/releases.html 解壓zookeeper
- 運行/bin/zkServer.cmd ,初次運行會報錯,沒有zoo.cfg配置文件,直接複製zoo_sample.cfg即可;當然,在Linux上運行zookeeper最好。
微服務提供者(provider)
- 在pom.xml導入依賴,主要是偷懶,如果不導入整合包,一個個導入也行。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加zk 3.4,9版本-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</version>
</dependency>
- 配置application.yml
server:
port: 8003
spring:
application:
name: cloud-provider-test
cloud:
zookeeper:
connect-string: localhost:2181
- 啓動類上添上註解
@SpringBootApplication
@EnableDiscoveryClient
public class TestProvider8004 {
public static void main(String[] args) {
SpringApplication.run(TestProvider8004.class,args);
}
}
微服務消費者(consumer)
- 在pom.xml導入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加zk 3.4,9版本-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</version>
</dependency>
- 配置yml
server:
port: 80
spring:
application: # 當前微服務的別名
name: cloud-consumer-text
cloud:
zookeeper:
connect-string: localhost:2181
- 主啓動類
@SpringBootApplication
@EnableDiscoveryClient
public class TestConsumer80 {
public static void main(String[] args) {
SpringApplication.run(TestConsumer80.class,args);
}
}
- 增加配置類(通信)
@Configuration
public class ApplicationContextConfig {
@LoadBalanced //負載均衡ribbon
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
服務調用
- HTTP:跟eureka一樣,可以使用ribbon或者封裝過的feign接口方式調用。(略)
- RPC:使用Dubbo框架。(感覺項目實現的步驟跟feign差不多~,都是接口調用)
- 在消費者端和提供者端的pom.xml中都導入依賴
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
- 服務端的application.yml修改相關配置
server:
port: 8008
dubbo:
application: #當前微服務名字
name: provider-server
registry: #註冊中心地址
address: zookeeper://127.0.0.1:2181
scan: #掃描指定包下服務
base-packages: top.hcode.service
service的實現類中添加相關注解,而TestService可以專門寫個api的maven模塊,這樣利用導入,這裏就直接寫在提供者裏面了。
import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
@Service //將服務發佈出去,注意應該是dubbo包下的
@Component //放在容器中
public class TestServiceImpl implements TestService{
@Override
public String test() {
return "(●'◡'●)";
}
}
項目啓動類添加註解@EnableDubboConfiguration
@SpringBootApplication
@EnableDubboConfiguration
public class DubboTest8008 {
public static void main(String[] args) {
SpringApplication.run(DubboTest8008.class, args);
}
}
這樣的話,dubbo就會掃描指定的包下帶有@component註解的服務,將它發佈在指定的註冊中心中。
- 消費者端的application.yml同樣也要添加dubbo的配置
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
配置application.yml
server:
port: 80
dubbo:
application: #當前應用名字
name: consumer-server
registry: #註冊中心地址
address: zookeeper://127.0.0.1:2181
直接將服務端的TestService接口拿過來,路徑必須保證正確,即和服務提供者相同,然後在添加消費端(如果已經將服務接口都寫在另一個maven裏面就可以直接在pom導入即可),這裏就需要自己寫。
@Service //注入到容器中
public class TestController {
@Reference //遠程引用指定的服務,他會按照全類名進行匹配,看誰給註冊中心註冊了這個全類名
private TestService testService;
@GetMapping("/test")
public void test(){ //直接調用~
testService.test();
}
}
項目啓動類添加註解@EnableDubboConfiguration
@SpringBootApplication
@EnableDubboConfiguration
public class DubboTest80 {
public static void main(String[] args) {
SpringApplication.run(DubboTest80.class, args);
}
}
nacos
Nacos就是註冊中心+配置中心的組合 ,擁有註冊中心的服務註冊與發現,springcloud config的遠程配置功能,還有springcloud bus消息總線的動態更新服務配置的功能,而且做到了不用像bus一樣需要每次都發請求提醒微服務配置已經更新,真正實現了動態更新配置。
下載後,解壓安裝包,windows直接運行bin目錄下的startup.cmd,Linux就運行startup.sh,docker就簡單多了。啓動後,運行成功後直接訪問http://localhost:8848/nacos,賬號密碼都是nacos,登錄即可監控服務。
服務提供者(provider)
- 導入pom依賴
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</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-actuator</artifactId>
</dependency>
- 配置yml
server:
port: 8010
spring:
application:
name: nacos-test-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址
# 暴露監控
management:
endpoints:
web:
exposure:
include: '*'
- 主啓動類添加註解
@EnableDiscoveryClient
@SpringBootApplication
public class TestNacos8010{
public static void main(String[] args) {
SpringApplication.run(TestNacos8010.class,args);
}
}
- controller和service就不寫了,跟之前一樣的。
服務消費者(consumer)
- 導入pom依賴
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</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-actuator</artifactId>
</dependency>
- 配置yml
server:
port: 80
spring:
application:
name: nacos-test-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
# 消費者將要去訪問的微服務名稱(註冊成功進入nacos的微服務提供者)
service-url:
nacos-user-service: http://nacos-test-provider
- 主啓動類添加註解
@EnableDiscoveryClient
@SpringBootApplication
public class TestNacos80
{
public static void main(String[] args)
{
SpringApplication.run(TestNacos80.class,args);
}
}
- 添加服務調用的template的配置類
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced //設置實現負載均衡,Ribbon
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
服務調用
肯定不是因我懶 不寫了,反正都差不多,也就feign和ribbon那種方式。註冊成功後,可以登錄nacos查看到服務的~,至於自動化配置下次再說。