1.微服务理论
独立应用变成一套小服务,每一个都运行在自己的进程内(容器) 独立业务能力 独立部署 独立开发语言 独立的数据存储
应该有一个能管理这些服务的中心
分布式系统是若干独立计算机的集合(多台服务器),这些计算机对于用户来说就像单个相关系统
集群:集群指的是将几台服务器集中在一起,实现同一业务。
集群就是很多服务器跑同一个项目
分布式与集群
== 分布式中的每一个节点 ==,都可以做集群。而集群并不一定就是分布式的。
RPC(Dubbo)
RestAPI (SpringCloud)
RPC是什么
RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范,dubbo是其实现
网络传输要求二进制,要序列化,打包(socket包)
高并发
工具限制(本身性能):
Tomcat 默认配置的最大请求数是 150,也就是说同时支持 150 个并发。当某个应用拥有 250 个以上并发的时候,应考虑应用服务器的集群。
系统限制
Windows 每个进程中的线程数不允许超过 2000
Linux 每个进程中的线程数不允许超过 1000
高并发衡量指标
高可用
服务集群部署,数据库双主机方式
主-备方式(Active-Standby方式)
主-备方式即指的是一台服务器处于某种业务的激活状态(即Active状态),另一台服务器处于该业务的备用状态(即Standby状态)。
双主机方式(Active-Active方式)
双主机方式即指两种不同业务分别在两台服务器上互为主备状态(即Active-Standby和Standby-Active状态)
版本选择
创建工程啥的就直接省略了。因为要引入的依赖是在是多呀,大概做法是先创建一个父工程cloud-paraent,再在该父工程下创建其余的工程。
还要安装一些插件,比如lombok,mybatisX以及一些idea中settings中的配置都省略

1、先保证cloud-consumer-order80 可以远程调用 cloud-provider-payment8001成功。
在消费端使用配置类配置bean对象RestTemplate
- @SpringBootConfiguration
- public class ApplicationContextConfig {
- @Bean
- public RestTemplate getRestTemplate(){
- return new RestTemplate();
- }
- }
并在controller层注入使用RestTemplate,使用以下方法实现远程调用
RestTemplate提供了多种便捷访问远程Http服务的方法
- restTemplate.getForObject()完成查询
- restTemplate.postForObject()完成添加
远程调用方法需要的三个参数
REST请求地址、请求参数、Http响应转换被转换成的对象类型。【其实看着都挺麻烦的,一会用OpenFeign替换】
- @RestController
- @Slf4j
- public class OrderController {
-
- public static final String PAYMENT_URL = "http://localhost:8001";
-
- @Resource
- private RestTemplate restTemplate;
-
- @PostMapping("/consumer/payment/create")
- public CommonResult
create(@RequestBody Payment payment){ - return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment, CommonResult.class);
- }
-
- @GetMapping("/consumer/payment/get/{id}")
- public CommonResult
getPayment(@PathVariable("id") Long id){ - return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
- }
- }
注意一个点,被远程调用的服务cloud-provider-payment8001的添加方法一定要使用@RequestBody,因为RESTAPI的风格就是http+json.
Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接
注册中心(存放服务地址相关信息(接口地址))
Eureka Server 提供服务注册服务
各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息。
Eureka Client 通过注册中心进行访问
是一个Java客户端,用于简化Eureka Server的交互。
--------
单机Eureka的构建步骤
IDEA生成eurekaServer端服务注册中心,也就是工程: cloud-eureka-server7001
这个工程特殊的地在于
1、引入以下依赖
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
- dependency>
2、同时在application.yml中做如下配置,一会浏览器访问 http://localhost:7001/
- server:
- port: 7001 # eureka的服务端
-
- eureka:
- instance:
- hostname: localhost #注册中心所在的服务器地址
-
- client:
- register-with-eureka: false #因为我就是服务端,不需要注册到Eureka中
- fetchRegistry: false #我就是服务端不需要从Eureka中获取信息
- service-url:
- defaultZone: http://localhost:7001/eureka # 注册中心的访问地址
3、在主启动类上加注解 @EnableEurekaServer
- @SpringBootApplication
- @EnableEurekaServer
- public class Application7001 {
- public static void main(String[] args) {
- SpringApplication.run(Application7001.class,args);
- }
- }
此时,启动工程 cloud-eureka-server7001,在浏览器端访问 http://localhost:7001/

在服务的提供者cloud-provider-payment8001和服务的消费者cloud-consumer-order80 中
都引入以下依赖,它俩都是Eurake的客户端
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
- dependency>
在配置文件application.yml中加入以下配置
提供者 cloud-provider-payment8001配置如下:
eureka: client: register-with-eureka: true #8001支付微服务 是客户端需要向注册中心注册信息 fetchRegistry: true #8001支付微服务 是客户端需要从注册中心获取信息 service-url: defaultZone: http://localhost:7001/eureka消费者 cloud-consumer-order80配置如下:
eureka: client: register-with-eureka: true fetchRegistry: true service-url: defaultZone: http://localhost:7001/eureka
分别在主启动类加上注解:@EnableEurekaClient
提供者 cloud-provider-payment8001主启动类如下:
@SpringBootApplication @MapperScan(basePackages = "com.atguigu.springcloud.dao") @EnableEurekaClient public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); } }消费者 cloud-consumer-order80主启动类如下:
@SpringBootApplication @EnableEurekaClient public class OrderMain80 { public static void main(String[] args) { SpringApplication.run(OrderMain80.class,args); } }
依次启动工程 7001,8001,80

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。
Ribbon目前也进入维护模式,未来替换方案是Spring Cloud LoadBalancer
LB负载均衡
将用户的请求平均分配到多个服务器上,从而达到系统的HA(高可用)。
Ribbon的本地负载均衡客户端 VS Nginx服务端负载均衡区别:
- Nginx是服务器负载均衡,客户端所有请求都会交给Nginx(http的服务器),然后由nginx实现转发请求到tomcat。即负载均衡是由服务器端完成的。
- Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用。
集中式LB(如Nginx)
进程内LB(如Ribbon)
Ribbon=负载均衡+RestTemplate调用
Ribbon在工作时分成两步:
第一步,先选择EurekaServer,它优先选择在同一个区域内负载较少的server。
第二步,再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址。其中Ribbon提供了多种策略。比如:轮询、随机和根据响应时间加权。
总结:Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。
Eureka客户端自带Ribbon的依赖,所以就没必要再引入下面的ribbon依赖
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-ribbonartifactId>
- dependency>
----------
Ribbon核心组件IRule
IRule 接口及实现类如下:
IRule:根据特定算法从服务列表中选取一个要访问的服务
- com.netflix.loadbalancer.RoundRobinRule 轮询,默认策略。
- com.netflix.loadbalancer.RandomRule 随机
- com.netflix.loadbalancer.RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务
- WeightedResponseTimeRule 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择(主动处理)
- BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
- AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例
- ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器
如何配置负载均衡策略
新建一个配置类,要特别注意该配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化订制的目的了。
- @SpringBootConfiguration
- public class MySelfRule {
- @Bean
- public IRule myRule(){
- return new RoundRobinRule();
- }
- }
主启动类添加@RibbonClient
在RestTemplate配置类上加注解,@LoadBalanced
在controller层修改代码,url不再是 http://localhost:8001
复刻8001,再生成8002的服务
做到这些还不够,现在只有8001的提供者,我们再给他复刻出来一个8002的服务
8001(右键复制)
想要上面那样的效果,需要快速运行设置
vm options: -Dserver.port=8002
意味着服务名一样,同一个服务多个实例
重启80服务,重新获取服务列表。
此时再测试就达到了负载均衡轮询的效果(很帅)
Ribbon负载均衡算法
rest接口第几次请求数%服务器集群总数量=实际调用服务器位置下标
每次服务重启动后rest接口计数从1开始。

HttpMessageConverters消息转交器
Feign是一个声明式的web服务客户端,Feign旨在使用编写Java Http客户端变得更容易。
Feign内置了 Ribbon
1、利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡。
2、与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。
OpenFeign是Spring Cloud 在Feign的基础上支持了SpringMVC的注解,如@RequestMapping。
引入依赖
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-openfeignartifactId>
- dependency>
在配置文件application.yml加入以下配置
- server:
- port: 80
- spring:
- application:
- name: cloud-consumer-feign-order80
- eureka:
- client:
- register-with-eureka: true
- fetch-registry: true
- service-url:
- defaultZone: http://localhost:7001/eureka
在主启动类加一个注解 @EnableFeignClients,不加@EnableEurekaClient也可以吗?也可以的
- @SpringBootApplication
- @EnableEurekaClient
- @EnableFeignClients
- public class OrderFeignMain80 {
- public static void main(String[] args) {
- SpringApplication.run(OrderFeignMain80.class,args);
- }
- }
之前使用Ribbon+RestTemplate,因为不符合编程习惯。咱还是喜欢三层架构,没有Service层浑身不爽啊,那就使用OpenFeign的方式
在Controller层,调用service层,接着啥也不管。就是这么任性,哼。让我想起了傲娇的央视六公主,在b站的简介,就一个字。哼~
@RestController public class OrderFeignController { @Resource private PaymentFeignService paymentFeignService; //调用远程的微服接口 @GetMapping(value = "/consumer/payment/get/{id}") public CommonResultgetPaymentById(@PathVariable("id") Long id){ //远程调用 return paymentFeignService.getPaymentById(id); } }
实现方式:接口+@FeignClient
新建PaymentFeignService接口并新增注解@FeignClient
- @Component
- @FeignClient(value = "CLOUD-PAYMENT-SERVICE") //下载注册中心的服务信息
- public interface PaymentFeignService {
- @PostMapping(value = "/payment/create")
- public CommonResult
create(@RequestBody Payment payment); -
- @GetMapping(value = "/payment/get/{id}")
- public CommonResult
getPaymentById(@PathVariable("id") Long id); - }
启动服务7001,8001,8002,openFeign80
浏览器测试
Feign自带负载均衡(轮询)配置项
OpenFeign超时控制
在服务提供者处故意暂停程序,模拟3秒的延迟

Feign说:我只等一秒(默认等待一秒),等不到就错误渲染
那肯定1秒是太短了呀,就要设置Feign超时时间,在application.yml中加入以下配置(顶格)
ribbon: ReadTimeout: 4000 # 读取 ConnectTimeout: 4000 # 连接