服务降级

        解决高并发的三把利器:降级、限流、缓存。

1 什么是服务降级

服务降级,当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务有策略的降低服务级别,以释放服务器资源,保证核心任务的正常运行。

2 服务降级方式

能够实现服务降级方式很多,常见的有如下几种情况:

  • 部分服务暂停
    系统可以访问,一部分业务权重相对低的服务暂时停止服务,例,某猫光棍节平台不通过修改收货地址、不可查看历史订单等;
  • 全部服务暂停
    系统不可访问,请求会被告知系统维护中,跳转至预设静态资源,例,12306在晚23点至次日早上7点不提供服务;
  • 随机拒绝服务
    系统可以访问,所有服务都提供,随机拒绝用户请求,按批次接收请求,在每批次中按照比例随机拒绝部分用户,例,部分平台访问过程中出现系统忙请重试;
  • 部分服务延迟
    系统可以访问,部分高峰功能采用延迟应答,即排队返回结果;

3 整个系统的服务降级埋点

有没有办法停掉rpcss 如何禁用rpc服务器_spring

网关路由:直接将请求路由到静态页面,即停止请求继续向下流转,返回静态资源给请求用户,全部服务暂停方式常用;

消费者:dubbo与springcloud的服务降级一般就指此处,消费者端接收请求后给出响应,停止服务继续流转,响应结果并不是提供者运算出来,而是预先设定的结果集,根据请求不同返回固定结果,减去后方处理压力;

数据缓存层:预先设定某种请求,如查询类请求,无论提交参数如何,只要是预设查询就返回既定结果,此结果就存放在数据缓存中,不需要在向下请求;

消息中间件:经常处理部分服务延迟方式,接收到请求,然后将请求放入MQ中进行排队等候处理,提供者处理完成后在给予响应;注意,如同部分服务延迟方式与其他三种方式不同一样,消息中间件的降级与其他埋点也有同样的不同,即最终返回结果一定是正确处理请求结果,而其他的降级处理返回的都是假设结果;

提供者:同样预设特定返回,不进入数据层查询,减去数据层压力,普遍约定不在提供者处做服务降级,因为此处再做意义不大,效率提升有限。

4 dubbo的服务降级采用Mock机制

Dubbo的服务降级采用的是mock机制,其具有两种降级处理方式:Mock Null降级处理,与Mock Class降级处理(推荐使用)。

5 Mock Null服务降级处理

降级处理在消费者埋点进行,因此无需创建提供者,同时也模拟提供者宕机情况下的降级处理逻辑;

(1) 创建消费者工程并引入依赖

创建消费者工程consumer-mocknull;

 

<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> 
	<!-- 自定义版本号 --> 
	<spring-version>4.3.16.RELEASE</spring-version> 
</properties> 
<dependencies>  
	<!-- dubbo依赖 --> 
	<dependency>
	    <groupId>org.apache.dubbo</groupId>
	    <artifactId>dubbo</artifactId>
	    <version>2.7.0</version>
	</dependency>

	<!-- Spring依赖 --> 
	<dependency> 
		<groupId>org.springframework</groupId> 
		<artifactId>spring-beans</artifactId> 
		<version>${spring-version}</version> 
	</dependency> 
	<dependency> 
		<groupId>org.springframework</groupId> 
		<artifactId>spring-core</artifactId> 
		<version>${spring-version}</version> 
	</dependency> 
	<dependency>
		<groupId>org.springframework</groupId> 
		<artifactId>spring-context</artifactId> 
		<version>${spring-version}</version> 
	</dependency> 
	<dependency> 
		<groupId>org.springframework</groupId> 
		<artifactId>spring-expression</artifactId> 
		<version>${spring-version}</version> 
	</dependency> 
	<dependency> 
		<groupId>org.springframework</groupId> 
		<artifactId>spring-aop</artifactId> 
		<version>${spring-version}</version> 
	</dependency> 
	<dependency> 
		<groupId>org.springframework</groupId> 
		<artifactId>spring-aspects</artifactId> 
		<version>${spring-version}</version> 
	</dependency> 
	<dependency> 
		<groupId>org.springframework</groupId> 
		<artifactId>spring-tx</artifactId> 
		<version>${spring-version}</version> 
	</dependency> 
	<dependency> 
		<groupId>org.springframework</groupId> 
		<artifactId>spring-jdbc</artifactId> 
		<version>${spring-version}</version> 
	</dependency> 
	
	<!-- zk客户端依赖:curator --> 
	<dependency> 
		<groupId>org.apache.curator</groupId> 
		<artifactId>curator-recipes</artifactId> 
		<version>2.13.0</version> 
	</dependency> <dependency> 
		<groupId>org.apache.curator</groupId> 
		<artifactId>curator-framework</artifactId> 
		<version>2.13.0</version> 
	</dependency>
	
	<!-- commons-logging依赖 --> 
	<dependency> 
		<groupId>commons-logging</groupId> 
		<artifactId>commons-logging</artifactId> 
		<version>1.2</version> 
	</dependency> 
</dependencies>

(2) 定义接口

public interface UserService {
	
	String getUsernameById(int id);
	void addUser(String username);
}

(3) 创建spring-consumer.xml配置文件

<!-- 添加 DUBBO SCHEMA -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
        
	<!-- 指定当前工程在Monitor监控中心显示的名称,一般与工程名相同 -->
	<dubbo:application name="consumer-morknull"/>
	<!-- 声明zookeeper注册中,单机zk -->
	<dubbo:registry address="zookeeper://192.168.85.129:2181" />
	
	<!-- 服务消费者-->
	<dubbo:reference id="userService" mock="return null" check="false"
					 interface="com.zxy.service.UserService"/>
</beans>

(5) 创建消费者启动类

/** 
 * Mock Null服务降级处理用户体验不好
 */
public class ConsumerRun {

	
	public static void main(String[] args) throws IOException {
		// 创建Spring容器
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-consumer.xml");
		//从容器中获取服务
		UserService service = (UserService)applicationContext.getBean("userService");
		
		//Mock Null服务降级处理对于有返回值的方法,其返回结果是null
		String usernameById = service.getUsernameById(5);
		System.out.println(usernameById);
		
		//Mock Null服务降级处理对于无返回值的方法,其没有任何返回结果
		service.addUser("dubbo");
	}

}

7 Mock Class服务降级处理

(1) 创建消费者工程导入依赖

创建工程consumer-mockclass,依赖与consumer-mocknull相同;

(2) 定义Mock Class

在业务接口所在的包中,本例为com.zxy.service包,定义一个类,该类的命名需要满足以下规则:业务接口简单类名 + Mock;

/**
 * 预设降级后返回结果 
 */
public class UserServiceMock implements UserService{

	@Override
	public String getUsernameById(int id) {
		return "没有此用户:"+id;
	}

	@Override
	public void addUser(String username) {

		System.out.println("添加用户失败:"+username);
	}

}

(3) 创建spring-consumer.xml

<!-- 添加 DUBBO SCHEMA -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
        
	<!-- 指定当前工程在Monitor监控中心显示的名称,一般与工程名相同 -->
	<dubbo:application name="9-consumer-morknull"/>
	<!-- 声明zookeeper注册中,单机zk -->
	<dubbo:registry address="zookeeper://192.168.85.129:2181" />
	
	<!-- 服务消费者-->
	<dubbo:reference id="userService" mock="true" check="false"
					 interface="com.zxy.service.UserService"/>
</beans>