SpringCloud框架笔记 (微服务架构&负载均衡&熔断器)

SpringCloud

微服务架构

每个工程都是独立的模块,工程之间使用更轻量的http通讯框架 (不建立依赖关系) 每个微服务都有自己的数据库,每个微服务都是完成模块的具体的功能,都是独立的,只需要对外提供一个接口

服务调用方式

RPC
  • 基于Socket
  • 自定义数据格式
  • 速度快,效率搞
  • 典型代表:Dubbo ElasticSearch集群间相互调用
Http
  • 基于TCP/IP
  • 规定数据传输格式
  • 缺点是消息封装比较臃肿,传输速度比较慢
  • 优点是对服务提供和调用没有任何技术限制,自由灵活,更符合微服务理念

ResTemplate

  • estTemplate是Rest的HTTP客户端模板工具类
  • 对基于Http的客户端进行封装
  • 实现对象与JSON的序列化与反序列化
  • 不限定客户端类型,目前常用的3种客户端都支持:HttpClient、OKHttp、JDK原生URLConnection(默认方式)
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringCloudDemo2RestemplateApplicationTest {
    @Autowired
    private RestTemplate restTemplate;
    @Test
    public void testRestTemplate(){
        String url="http://localhost:18081/user/list";
        String json=restTemplate.getForObject(url,String.class);
        System.out.println(json);
    }
}

要先在起步引导类中创建Restemplate的Bean容器,也就是在服务消费者使用ResTemplate调用服务提供者,使用ResTemplate调用的时候,需要先创建并注入到SpringIOC容器中

@SpringBootApplication
public class UserConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserConsumerApplication.class,args);
    }
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

SpringBoot框架中为我们提供了实现类的注解,所有大部分情况我们都不再需要写sql语句

  • @Entity 表示业务实体 标识这是一个Spring要创建的Bean
  • @Table (name=“数据库表名”) 映射表名
  • @Column(name=" ") 如果数据库字段名与对象名不相同时,要加上此注解,并指定数据库字段名
  • @Transient 排除数据库字段,当一个普通java对象属性使用
  • @Id 映射当前属性是主键
  • @GeneratedValue (strategy=GenerationType.IDENTITY) 主键自增
@Entity  //表示业务实体,标识这是spirng要创建的javaBean类
@Table(name = "tb_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;//主键id
    private String username;//用户名
    private String password;//密码
    private String name;//姓名
    private Integer age;//年龄
    private Integer sex;//性别 1男性,2女性
    private Date birthday; //出生日期
    private Date created; //创建时间
    private Date updated; //更新时间
    private String note;//备注
   //Get和Set方法

注意:Dao接口继承JpaRespository<T,Id> T: 目标类(实现类) id:主键类型

public interface UserDao extends JpaRepository<User,Integer> {
}

注册中心 Eureka

运行原理
  • ApplicationServicet 服务提供者注册到EurkeServer(注册服务名字) 服务提供者会通过http方式定时向注册中心发送心跳信息(默认90S),表示服务存活

  • ApplicationClient 服务消费者在启动的那一刻,会向注册中心调用需要的服务名单,拿到名单后直接通过ip和地址向服务提供者进行数据调用

  • EurekaServer注册中心会定时向客户端消费者发送生产者名单(默认30S)

注册中心的搭建
    <!--eureka-server依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
application.yml
server: 
	port: 7001
spring: 
	application: 
		name: eureka-server
eureka: 
	client: 
		register-with-eureka: false
		fetch-registry: false 
		service-url: 
			defaultZone: http://localhost:7001/eureka
           

在起步引导类中加入@EnableEurekaServer 注解
@SpringBootApplication
@EnableEurekaServer //开启Eureka服务
public class EurekaServerApplication {public static void main(String[] args) {        SpringApplication.run(EurekaServerApplication.class,args);    }}
生产者完成注册

依赖

<dependency>    
    <groupId>org.springframework.cloud</groupId>    
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml 配置文件

server: 
	port: 18081
spring: 
	datasource:
		driver-class-name: com.mysql.cj.jdbc.Driver
		username: root
		password: root
		url: 
		jdbc:mysql://192.168.13.100/test?seUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
	application: 
		name: user-provider  #服务的名字,不同的应用,名字不同,如果是集群,名字需要相同
		
#指定eureka服务地址		
eureka: 
	client: 
		service-url:
			defaultZone: http://localhost:7001/eureka
	

在起步引导类中使用注解开启客户端发现功能 @EnableDiscoveryClient

@EnableEurekaClient  //开启客户端发现功能

起步引导类要加上 (二选一)

  • @EnableEurekaClient 仅支持 Eureka
  • @EnableDiscoveryClient 不仅支持Eureka,还可以支持zookeeper
消费者完成注册
  @RequestMapping(value = "/{id}")
    public User queryById(@PathVariable(value = "id")Integer id){
        //根据服务名获取到实体数据集合
        List<ServiceInstance> instances = discoveryClient.getInstances("user-provider");
        ServiceInstance serviceInstance = instances.get(0);
        //此时获取到的host是主机名,注意:要是想使用ip地址,必须再在服务提供者的配置文件中配置instance属性
        String url="http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/user/find/"+id;
        return restTemplate.getForObject(url,User.class);
    }

**注意: 要是想使用ip地址,必须再在服务提供者的配置文件中配置instance属性 **

#指定eureka服务地址
eureka:
  client:
    service-url:
      # EurekaServer的地址
      defaultZone: http://localhost:7001/eureka
  instance:
    #指定IP地址
    ip-address: 127.0.0.1
    #访问服务的时候,推荐使用IP
    prefer-ip-address: true
Eureka配置详解
服务注册
  1. 当我们开启了客户端发现注解@DiscoveryClient 同时导入 enureka-client依赖坐标
  2. 同时配置Eureka服务注册中心地址在配置文件中
  3. 服务在启动时,会检测是否有@DiscoveryClient 注解和配置信息
  4. 如果有,则会向注册中心发起注册请求,携带服务元数据信息(IP, 端口等)
  5. Eureka 注册中心会把服务的信息保存在Map中
服务续约
  1. 服务注册完成以后,服务提供者会维持一个心跳,保存服务处于存在状态.这个称之为服务续约(renew)

    #租约到期,服务失效时间,默认值90秒   
    lease-expiration-duration-in-seconds: 150   
    #租约续约间隔时间,默认30秒
    lease-renewal-interval-in-seconds:30
    

服务超过90秒没有发生心跳,EurekaServer会将服务从列表中移除, 前提是EurekServer关闭了自我保护

获取服务列表

服务消费者启动时,会检测是否获取服务注册信息配置,如果是,则会EurekaServer 服务列表获取只读备份,缓存到本地,每隔30秒,会重新获取并更新数据, 时间可以通过registry-fetch-interval-seconds修改

#每隔30秒获取服务列表(只读备份)  
registry-fetch-interval-seconds: 30
失效剔除
server: 
#服务中心每隔一段时间(默认60秒) 将清单中的没有续约的服务剔除,单位是毫秒
	eviction-interval-timer-in-ms: 5000
自我保护

Eureka 会统计服务实例最近15分组心跳续约的比例是否低于85%,如果低于,则会触发自我保护机制. 服务中心页面会显示提示信息

  • 自我保护模式下,不会剔除任何服务实例
  • 自我保护模式保证了大多数服务依然可用
  • 通过enable-self-preservation 配置可以关停自我保护
#关闭自我保护功能,默认是打开的
enable-self-preservation: false

Spring Cloud Ribbon 负载均衡

Ribbon简介

Ribbon是Netflix发布的负载均衡器,有助于控制Http客户端行为. 为Ribbon配置服务提供者地址列表后,Ribbon就可以基于负载均衡算法,自动帮助服务消费者请求.

Ribbon默认提供的负载均衡算法: 轮循,随机,重试法,加权 还可以自定义一负载均衡算法

入门使用

在消费者的ResTemplate容器方法上加上@LoadBalanced注解 表示客户端开启负载均衡 (无需引入依赖)

    @Bean
    @LoadBalanced //开启负载均衡
    public RestTemplate restTemplate(){
        return new RestTemplate();}}

修改消费者的调用方式,不再需要手动获取Ip和端口,改为通过服务名调用

    @RequestMapping(value = "/{id}")
    public User queryById(@PathVariable(value = "id")Integer id){
      /*  List<ServiceInstance> instances = discoveryClient.getInstances("user-provider");
        ServiceInstance serviceInstance = instances.get(0);
        String url="http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/user/find/"+id;*/
      //使用负载均衡后就不需要再手动获取ip和端口,而是直接通过服务名称调用
        String url="http://user-provider/user/find/"+id;
        return restTemplate.getForObject(url,User.class);
    }
负载均衡策略配置

在消费者中配置更该轮循策略 (真实环境下只选其一)

# 修改服务地址轮询策略,默认是轮询,配置之后变随机
user-provider:
  ribbon:
    #轮询
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
    #随机算法
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    #重试算法,该算法先按照轮询的策略获取服务,如果获取服务失败则在指定的时间内会进行重试,获取可用的服务
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule
    #加权法,会根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越大。刚启动时如果同统计信息不足,则使用轮询的策略,等统计信息足够会切换到自身规则。
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.ZoneAvoidanceRule
Ribbo负载均衡原理

负载均衡器动态的从服务中心获取到服务提供者的访问地址(host,port),LoadBalancerInterceptor这个类会对ResTemplate的请求进行拦截,然后从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真正服务地址信息,替换服务id


Spring Cloud Hystrix 熔断器

  • Hystrix也是Netflix公司的一款组件
  • Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库、防止出现级联失败也就是雪崩效应
  • Hystrix解决雪崩问题的手段,主要是通过服务降级(兜底),线程隔离
熔断器状态有三种
  • closed: 关闭状态 所有请求正常访问
  • Open: 打开状态 所有请求都会被降级
  • Half Open: 半开状态 Open状态不是永久,打开一会后会进入休眠时间(默认5秒). 休眠时间过后进入半开状态
    • 半开状态: 熔断器会判断下一次请求的返回状况,如果成功,熔断器切回Closed状态.如果失败,熔断器切回open状态
熔断器的核心
  1. 线程隔离: 是指Hystrix 为每一个依赖服务调用一个小的线程,如果线程池用尽,调用立即被拒绝,默认不采用排队
  2. 服务降级(兜底方法): 优先保证核心服务,而非核心服务不可用或弱可用.触发Hystrix服务降级的情况: 线程池已满,请求超时
快速入门

添加依赖

<!--熔断器-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

在消费者的起步引导类中添加@EnableCircuitBreaker 注解 表示开启熔断

@EnableCircuitBreaker  //开启熔断

在Contoller层添加方法

   /**
     * 服务降级处理方法
     * @param id
     * @return
     */
    public User failBack(Integer id){
        User user=new User();
        user.setUsername("服务降级,默认处理");
        return user;
    }

在Controller的Servlet入口方法上添加注解@HystrixCommand(fallbackMethod=" 服务降级处理方法名")

 @RequestMapping(value = "/{id}")
    @HystrixCommand(fallbackMethod = "failBack") //方法如果处理出问题,就调用降级处理方法
    public User queryById(@PathVariable(value = "id")Integer id){...}
其它熔断配置
  • 熔断后休眠时间: sleepWindowInMilliseconds
  • 熔断触发最小次数: requestVolumeThreshold
  • 熔断触发错误比列阈值: errorThresholdPercentage
  • 熔断超时时间: timeoutInMilliseconds

配置熔断策略

hystrix:
	command: 
	  default:
		 circuitBreaker:	
		 #强制打开熔断器,默认false关闭的,测试配置是否生效,打开后,所有的请求都会被拒绝
			forceOpen: false
			#熔断最小请求次数,默认值是20,允许同时请求的线程数
			requestVolumeThreshold: 10
			#触发熔断错误比列阈值,默认值百分之50  例如:如果上面是10,经过参数后是5
			errorThresholdPercentage: 50
			#熔断后休眠时长,默认五秒
			sleepWindowInMilliseconds: 10000
		 execution: 
			isolation:
				thread:
				#熔断超时时间   默认1秒
					timeoutInMilliseconds: 1000

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值