1. 系統架構演變概述
2. 微服務架構說明
SOA使用了ESB組件的面向服務架構:ESB自身實現復雜;應用服務粒度較大,所有服務之間的通信都經過ESB會降低通信速度;部署、測試ESB比較麻煩。
微服務架構:是一套使用小服務或者單一業務來開發單個應用的方式或途徑。
微服務架構特點:
- 單一職責
- 服務粒度小
- 面向服務(對外暴露REST api)
- 服務之間相互獨立
與使用ESB的SOA架構的區別:微服務架構沒有使用ESB,有服務治理注冊中心;業務粒度小。
3. 服務調用方式說明
- RPC:基于socket,速度快,效率高;webservice、dubbo
- HTTP:基于TCP,封裝比較臃腫;對服務和調用方沒有任何技術、語言的限定,自由靈活;RESTful,Spring Cloud
4. Spring RestTemplate示例工程導入
一般情況下有如下三種http客戶端工具類包都可以方便的進行http服務調用:
- httpClient
- okHttp
- JDK原生URLConnection
spring 提供了RestTemplate的工具類對上述的3種http客戶端工具類進行了封裝,可在spring項目中使用RestTemplate進行服務調用。
@RunWith(SpringRunner.class)
@SpringBootTest
public class RestTemplateTest {@Autowiredprivate RestTemplate restTemplate;@Testpublic void test(){String url = "http://localhost/user/8";//restTemplate可以對json格式字符串進行反序列化User user = restTemplate.getForObject(url, User.class);System.out.println(user);}
}
5. Spring Cloud概述
- 整合的組件可以有很多組件;常見的組件有:eureka注冊中心,Gateway網關,Ribbon負載均衡,Feign服務調用,Hystrix熔斷器。在有需要的時候項目添加對于的啟動器依賴即可。
- 版本特征:以英文單詞命名(倫敦地鐵站名)
6. 創建微服務工程
需求:查詢數據庫中的用戶數據并輸出到瀏覽器
- 父工程heima-springcloud:添加spring boot父坐標和管理其它組件的依賴
- 用戶服務工程user-service:整合mybatis查詢數據庫中用戶數據;提供查詢用戶服務
- 服務消費工程consumer-demo:利用查詢用戶服務獲取用戶數據并輸出到瀏覽器
小結:
<!-- springCloud --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency>
通過 scope
的import可以繼承 spring-cloud-dependencies
工程中的依賴
7. 搭建配置user-service工程
需求:可以訪問http://localhost:9091/user/8輸出用戶數據
實現步驟:
- 添加啟動器依賴(web、通用Mapper);
- 創建啟動引導類和配置文件;
- 修改配置文件中的參數;
- 編寫測試代碼(UserMapper,UserService,UserController);
- 測試
- 添加啟動器依賴
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 通用Mapper啟動器 --><dependency><groupId>tk.mybatis</groupId><artifactId>mapper-spring-boot-starter</artifactId></dependency><!-- mysql驅動 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies>
- 編寫配置文件
server:port: 9091
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/springcloudusername: rootpassword: rootmybatis:type-aliases-package: com.itheima.user.pojo
8. 搭建配置consumer-demo工程
目標:編寫測試類使用restTemplate訪問user-service的路徑根據id查詢用戶
分析:
需求:訪問http://localhost:8080/consumer/8 使用RestTemplate獲取http://localhost:9091/user/8的數據
實現步驟:
- 添加啟動器依賴;
- 創建啟動引導類(注冊RestTemplate)和配置文件;
- 編寫測試代碼(ConsumerController中使用restTemplate訪問服務獲取數據)
- 測試
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>
@SpringBootApplication
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}@Beanpublic RestTemplate get(){return new RestTemplate();}
}
@RestController
@RequestMapping("/consumer")
public class ConsumerController {@Autowiredprivate RestTemplate restTemplate;@GetMapping("/{id}")public User get(@PathVariable long id){return restTemplate.getForObject("http://localhost:9091/user/"+id, User.class);}}
- 服務管理
如何自動注冊和發現
如何實現狀態監管
如何實現動態路由 - 服務如何實現負載均衡
- 服務如何解決容災問題
- 服務如何實現統一配置
上述的問題都可以通過Spring Cloud的各種組件解決。
9. Eureka注冊中心說明
Eureka的主要功能是進行服務管理,定期檢查服務狀態,返回服務地址列表。
10. 搭建eureka-server工程
Eureka是服務注冊中心,只做服務注冊;自身并不提供服務也不消費服務。可以搭建web工程使用Eureka,可以使用Spring Boot方式搭建。
搭建步驟:
- 創建工程;
- 添加啟動器依賴;
- 編寫啟動引導類(添加Eureka的服務注解)和配置文件;
- 修改配置文件(端口,應用名稱…);
- 啟動測試
小結:
- 啟動器依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency>
- 配置文件
server:port: 10086
spring:application:name: eureka-server
eureka:client:service-url:# eureka 服務地址,如果是集群的話;需要指定其它集群eureka地址defaultZone: http://127.0.0.1:10086/eureka# 不注冊自己register-with-eureka: false# 不拉取服務fetch-registry: false
11. 服務注冊與發現
- 服務注冊:在服務提供工程user-service上添加Eureka客戶端依賴;自動將服務注冊到EurekaServer服務地址列表。
- 添加依賴;
- 改造啟動引導類;添加開啟Eureka客戶端發現的注解;
- 修改配置文件;設置Eureka 服務地址
- 服務發現:在服務消費工程consumer-demo上添加Eureka客戶端依賴;可以使用工具類根據服務名稱獲取對應的服務地址列表。
- 添加依賴;
- 改造啟動引導類;添加開啟Eureka客戶端發現的注解;
- 修改配置文件;設置Eureka 服務地址;
- 改造處理器類ConsumerController,可以使用工具類DiscoveryClient根據服務名稱獲取對應服務地址列表。
添加依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
修改配置文件
eureka:client:service-url:defaultZone: http://127.0.0.1:10086/eureka
服務注冊
@SpringBootApplication
@MapperScan("com.gogo.mapper")
@EnableDiscoveryClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class,args);}
}
服務發現
@RestController
@RequestMapping("/consumer")
public class ConsumerController {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;@GetMapping("/{id}")public User get(@PathVariable long id){List<ServiceInstance> instances = discoveryClient.getInstances("user-service");ServiceInstance serviceInstance = instances.get(0);return restTemplate.getForObject("http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/user/"+id, User.class);}}
12. Eureka Server高可用配置
分析:
Eureka Server是一個web應用,可以啟動多個實例(配置不同端口)保證Eureka Server的高可用。
高可用配置:將Eureka Server作為一個服務注冊到其它Eureka Server,這樣多個Eureka Server之間就能夠互相發現對方,同步服務,實現Eureka Server集群。
13. Eureka客戶端與服務端配置
配置eureka客戶端user-service的注冊、續約等配置項,配置eureka客戶端consumer-demo的獲取服務間隔時間;了解失效剔除和自我保護
- Eureka客戶端工程
- user-service 服務提供
- 服務地址使用ip方式
- 續約
- consumer-demo 服務消費
- 獲取服務地址的頻率
- user-service 服務提供
- Eureka服務端工程 eureka-server
- 失效剔除
- 自我保護
- user-service
eureka:client:service-url:defaultZone: http://127.0.0.1:10086/eurekainstance:# 更傾向使用ip地址,而不是host名prefer-ip-address: true# ip地址ip-address: 127.0.0.1# 續約間隔,默認30秒lease-renewal-interval-in-seconds: 5# 服務失效時間,默認90秒lease-expiration-duration-in-seconds: 5
- consumer-demo
eureka:client:service-url:defaultZone: http://127.0.0.1:10086/eureka# 獲取服務地址列表間隔時間,默認30秒registry-fetch-interval-seconds: 10
- eureka-server
eureka:server:# 服務失效剔除時間間隔,默認60秒eviction-interval-timer-in-ms: 60000# 關閉自我保護模式(默認是打開的)enable-self-preservation: false
15. Ribbon負載均衡應用
分析:
需求:可以使用RestTemplate訪問http://user-service/user/8獲取服務數據。
可以使用Ribbon負載均衡:在執行RestTemplate發送服務地址請求的時候,使用負載均衡攔截器攔截,根據服務名獲取服務地址列表,使用Ribbon負載均衡算法從服務地址列表中選擇一個服務地址,訪問該地址獲取服務數據。
實現步驟:
- 啟動多個user-service實例(9091,9092);
- 修改RestTemplate實例化方法,添加負載均衡注解;
- 修改ConsumerController;
- 測試
@SpringBootApplication
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}@Bean@LoadBalancedpublic RestTemplate get(){return new RestTemplate();}
}
@RestController
@RequestMapping("/consumer")
public class ConsumerController {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;@GetMapping("/{id}")public User get(@PathVariable long id){List<ServiceInstance> instances = discoveryClient.getInstances("user-service");ServiceInstance serviceInstance = instances.get(0);return restTemplate.getForObject("http://"+"user-service"+"/user/"+id, User.class);}}
小結:
在實例化RestTemplate的時候使用@LoadBalanced,服務地址直接可以使用服務名。
16. 熔斷器Hystrix簡介
目標:了解熔斷器Hystrix的作用
小結:
Hystrix是一個延遲和容錯庫,用于隔離訪問遠程服務,防止出現級聯失敗。
17. 線程隔離&服務降級
Hystrix解決雪崩效應:
-
線程隔離:用戶請求不直接訪問服務,而是使用線程池中空閑的線程訪問服務,加速失敗判斷時間。
-
服務降級:及時返回服務調用失敗的結果,讓線程不因為等待服務而阻塞。
-
consumer-demo中添加依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>
- 開啟熔斷
@SpringCloudApplication
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}@Bean@LoadBalancedpublic RestTemplate get(){return new RestTemplate();}
}
- 降級邏輯
@RestController
@RequestMapping("/consumer")
@Slf4j
@DefaultProperties(defaultFallback = "defaultFall")
public class ConsumerController {@Autowiredprivate RestTemplate restTemplate;@GetMapping("/{id}")
/* @HystrixCommand(fallbackMethod = "fall")*/@HystrixCommandpublic String get(@PathVariable long id){return restTemplate.getForObject("http://"+"user-service"+"/user/"+id, String.class);}public String fall(long id){log.error("查詢{}失敗",id);return "網絡太差了";}public String defaultFall(){return "默認網絡太差了";}}
- 修改超時配置
hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 2000
18. 服務熔斷演示
@RestController
@RequestMapping("/consumer")
@Slf4j
@DefaultProperties(defaultFallback = "defaultFall")
public class ConsumerController {@Autowiredprivate RestTemplate restTemplate;@GetMapping("/{id}")
/* @HystrixCommand(fallbackMethod = "fall")*/@HystrixCommandpublic String get(@PathVariable long id){
if(id==1) throw new RuntimeException("不行的");return restTemplate.getForObject("http://"+"user-service"+"/user/"+id, String.class);}public String fall(long id){log.error("查詢{}失敗",id);return "網絡太差了";}public String defaultFall(){return "默認網絡太差了";}}
hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 2000circuitBreaker:errorThresholdPercentage: 50 # 觸發熔斷錯誤比例閾值,默認值50%sleepWindowInMilliseconds: 10000 # 熔斷后休眠時長,默認值5秒requestVolumeThreshold: 10 # 熔斷觸發最小請求次數,默認值是20