服务降级及dubbo中的实现示例
经历过12306抢票的人应该经常会遇到这个问题:在抢票高峰的时候,明明票还有,但是查询出来的列表却是为空的(如果没票列表也应该会呈现);等高峰过后再查询,列表又恢复正常。个人猜测应该是查询过程中出现了问题,要么超时,要么网络问题导致查询失败采用的服务降级处理。所以,最终呈现给用户的并不是内部系统出错之类的提示,而是一个空的列表。
服务降级,当服务器压力剧增时,根据当前业务情况及流量对一些服务和页面有策略的降级,以此缓解了服务器资源压力,以保证核心任务的正常运行,同时也保证了部分甚至大部分客户得到正确响应。
服务降级实施策略
- 页面拒绝服务:页面提示由于服务繁忙此服务暂停。跳转到varnish或nginx的一个静态页面。
- 服务接口拒绝服务:无用户特定信息的页面能访问,提示服务器繁忙。页面内容也可在缓存(Varnish)或CDN内获取。
- 延迟持久化:页面访问照常,但是涉及记录变更,会提示稍晚能看到结果,将数据记录到异步队列或log,服务恢复后执行。
- 随机拒绝服务:服务接口随机拒绝服务,让用户重试,目前较少采用。因为用户体验不佳。
服务降级埋点
- 消息中间件
所有API调用请求可以使用消息中间件进行控制,这可以有效地处理请求流量的增长,避免服务压力过大,导致服务雪崩效应。缺点是,增加了服务处理和业务处理的复杂性。 - 前端页面
指定网址不可访问(NGINX等load balance来处理),处理简单。缺点是用户体验非常不好。 - 底层数据层
拒绝所有增删改动作,只允许查询。此时用户可以查看所有的查询处理页面和业务,但无法进行有更新修改的操作。
管理方式
直觉管理方式:运维人员可以指定哪些模块降级。
当服务器检测到压力增大,服务器监测自动发送通知给运维人员,运维人员根据自己或相关人员判断后通过配置平台设置当前运行等级来降级。降级首先可以对非核心业务进行接口降级。如果效果不显著,开始对一些页面进行降级,以此保证核心功能的正常运行。
分级管理方式:运维人员无需关心业务细节,直接按级别降低即可。
业务确定好对应业务的优先级别,指定好分级降级方案。当服务器检测到压力增大,服务检测自动发送通知给运维人员。运维人员根据情况选择运行等级.
而各个应用还可以根据自己的级别自动判断是否工作,如何拒绝
在dubbo平台上实现服务降级
最后,在dubbo中想实现服务降级,需要怎么样做可以实现?
dubbo中的处理
dubbo开发中,可能由于服务没有启动或者网络不通,调用中会出现RpcException,也就是远程调用失败。如果是服务启动顺序的问题,可能加工check=”false”的配置可以得到很好的解决。但是,如果是服务宕掉或者并发数太高导致的RpcException该如何处理?
查看dubbo的官方文档,可以发现有个mock的配置,mock只在出现非业务异常(比如超时,网络异常等)时执行。mock的配置支持两种,一种为boolean值,默认的为false。如果配置为true,则缺省使用mock类名,即类名+Mock后缀;另外一种则是配置”return null”,可以很简单的忽略掉异常。
一个示例
服务接口
/**接口定义*/
public interface IUser {public void addUser(User u);public User getUserById(int id);}/**实现类*/
public class UserImpl implements IUser {private static List<User> USER_LIST = new ArrayList<User>();static{for(int i=0;i<10;i++){User u = new User();u.setAddress("address"+i);u.setId(i);u.setName("name"+i);USER_LIST.add(u);}}public void addUser(User u) {USER_LIST.add(u);System.out.println("total:"+USER_LIST.size());}public User getUserById(int id) {for(int i=0;i<USER_LIST.size();i++){if(USER_LIST.get(i).getId() == id){return USER_LIST.get(i);}}return null;}
}
服务提供方的配置:
dubbo-provider.xml
<?xml version="1.0" encoding="UTF-8"?><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"><!-- 提供方应用信息,用于计算依赖关系 --><dubbo:application name="hello-world-app" /><!-- 使用multicast广播注册中心暴露服务地址 --><dubbo:registry address="zookeeper://127.0.0.1:2181" /><!-- 用dubbo协议在20880端口暴露服务 --><dubbo:protocol name="dubbo" port="20880" /><!-- 声明需要暴露的服务接口 --><dubbo:service interface="com.dubbosample.iface.IUser" ref="userImpl" timeout="10000" /><!-- 和本地bean一样实现服务 --><bean id="userImpl" class="com.dubbosample.ifaceimpl.UserImpl" /></beans>
服务调用方的配置:
<?xml version="1.0" encoding="UTF-8"?><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"><!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 --><dubbo:application name="dubbo-consumer" /><dubbo:registry address="zookeeper://127.0.0.1:2181" /><!-- 生成远程服务代理,可以和本地bean一样使用demoService --><dubbo:reference id="iUser" interface="com.dubbosample.iface.IUser" timeout="10000" check="false" mock="return null"></dubbo:reference></beans>
服务调用的测试代码:
public static void main(String[] args) throws Exception{ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"classpath:dubbo-consumer.xml"});context.start();IUser iUser = (IUser)context.getBean("iUser");User u = new User();u.setAddress("aaa");u.setId(311);u.setName("n3");iUser.addUser(u);System.out.println(iUser.getUserById(1));}
测试时,如果服务启动,则程序按照预期的运行正常;如果服务没启动,则此时运行程序,程序并未报错,输出数据为null。
说明
通过以上的例子可以知道,通过mock的配置,可以很好的实现dubbo服务降级。但是,仔细查看上面的例子会发现,IUser本身定义了两个接口,一个是新增用户,一个是根据id查询用户信息。对于根据id查询用户信息,在调用失败的时候返回null很好理解,可能是由于验证失败或者记录删除了,但是对于新增用户,可能就需要抛出具体的业务信息,否则程序无法处理后续的业务,包括页面弹出”添加成功“或者列表刷新的时候无法查看到最新的记录,这样体验将会非常不好。所以,如果要有较好的区分,可以通过以下的方式,可以更好的实现降级:
(1)将接口进行归类,分成查询操作类、变更操作类:对于查询的操作分为一个接口类,变更的归类为其他的接口类,这样对于查询的可以使用mock=”return null”进行降级操作;对于变更类的操作接口,可以仍旧使用try……catch进行异常捕获处理;
(2)配置mock=”true”,同时mock实现接口,接口名要注意命名规范:接口名+Mock后缀。此时如果调用失败会调用Mock实现。mock实现需要保证有无参的构造方法。
配置mock=”true”的情况,对于上面的例子即在IUser的同个路径下,添加类IUserMock,实现如下:
public class IUserMock implements IUser {@Overridepublic void addUser(User u) {throw new RuntimeException("add user fail!");}@Overridepublic User getUserById(int id) {return null;}
}
服务降级及dubbo中的实现示例相关推荐
- dubbo源码解析-逻辑层设计之服务降级
Dubbo源码解析系列文章均来自肥朝简书 前言 在dubbo服务暴露系列完结之后,按计划来说是应该要开启dubbo服务引用的讲解.但是现在到了年尾,一些朋友也和我谈起了明年跳槽的事.跳槽这件事,无非也 ...
- 微服务服务降级与熔断
目录 1:服务降级 1.1 feign实现服务降级 1.2 Hystrix实现服务降级 2:服务熔断 2.1 熔断机制 2.2 Consumer侧引入pom 2.3 在Consumer侧启动类开启熔断 ...
- Dubbo的负载均衡、集群容错、服务降级等机制详解
文章目录 1. Dubbo与RPC的关系 2. Dubbo的基本使用 2.1 Dubbo是什么? 2.2 负载均衡 2.3 服务超时 2.4 集群容错 2.5 服务降级 2.6 本地存根 2.7 参数 ...
- dubbo 服务降级
dubbo 服务降级 官网:https://dubbo.apache.org/zh/docs/advanced/local-mock/ 服务降级 应用:消费端服务调用失败,不抛出异常,返回默认的数据 ...
- dubbo中对服务多版本的支持
dubbo中对服务多版本的支持 在dubbo的文档中说: 当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用. 在低压力时间段,先升级一半提供者为新版本 再将所有消费者升 ...
- dubbo 支持服务降级吗_dubbo面试题!会这些,说明你真正看懂了dubbo源码
整理了一些dubbo可能会被面试的面试题,感觉非常不错.如果你基本能回答说明你看懂了dubbo源码,对dubbo了解的足够全面.你可以尝试看能不能回答下.我们一起看下有哪些问题吧? dubbo中&qu ...
- 分布式面试 - 如何基于 dubbo 进行服务治理、服务降级、失败重试以及超时重试?
分布式面试 - 如何基于 dubbo 进行服务治理.服务降级.失败重试以及超时重试? 面试题 如何基于 dubbo 进行服务治理.服务降级.失败重试以及超时重试? 面试官心理分析 服务治理,这个问题如 ...
- Dubbo(十四) dubbo的服务降级与集群容错
一.dubbo的服务降级 dubbo的服务降级包含两种常见,屏蔽服务和服务容错.在dubbo-admin服务信息消费者界面可以看到有屏蔽和容错功能. 屏蔽功能是将该服务直接进行屏蔽,消费者将不再调用服 ...
- 面试系列26 如何基于dubbo进行服务治理、服务降级、失败重试以及超时重试
(1)服务治理 1)调用链路自动生成 一个大型的分布式系统,或者说是用现在流行的微服务架构来说吧,分布式系统由大量的服务组成.那么这些服务之间互相是如何调用的?调用链路是啥?说实话,几乎到后面没人搞的 ...
最新文章
- Webpack 源码学习系列(一)
- 树莓派4温度压力测试方法
- android cts 编译,使用 Android studio 分析运行 CTS 用例
- 拥抱.NET Core系列:依赖注入(2)
- win7链接html线到屏幕上,为你解决win7系统html文件图标变成空白的具体技巧 - win7吧...
- linux 单用户密码修改
- LNMP与CA认证的童话故事
- pytorch torch.randint
- OAuth2.0资源服务器之校验Token配置
- 禅道备份功能_禅道备份处理
- 遗传算法图解_遗传算法图解指南
- 详解Java 堆排序
- matlab imcrop 细节分析
- 用VBA检查Word文档中是否存在位于行首的脚注引用,如存在则通过调整字符间距使其移动到非行首的位置
- QT虚拟键盘中英文切换
- 30分钟了解蒙特卡洛方法
- css绘制卡券优惠券_用纯css来实现一个优惠券
- linux把m4s格式转换mp4,史上最详细!如何将B站缓存的m4s文件无损转换为mp4格式
- jQuery实现图片卡片层叠式切换效果
- Joshua Porter 20条UI设计原则
热门文章
- php-fpm的pool - 慢执行日志 - 进程管理 - open_basedir
- 第一次使用最新开发的在线编辑器讲课记录笔记
- Windows 平台安装 MongoDB教程
- 在VMware Workstation中批量创建上千台虚拟机(上)
- 用python查找指定格式或名称的文件及修改指定文件夹名称
- 用Java编写模仿的太阳系(九星行旋转)--原创
- list python 转tensor_Tensorflow模型量化4 --pb转tflite(uint8量化)小结
- Ubuntu 安装 Tomcat 7.0.40
- jBPM4.4 window下启动tomcat
- mysql切换到使用openssl,MySQL主从复制+OpenSSL