降级服务是什么,服务降级怎么处理的

作者简介:曾任职于阿里巴巴,每日优鲜等互联网公司,任技术总监,15年电商互联网经历。

提起服务降级,估计很多人都听说过,但是又因为亲身经历不多,所以可能不是很理解。本文我们会结合具体实例从多方面详细阐述服务降级。

写在前面

互联网分布式系统中,经常会有一些异常状况导致服务器压力剧增,比如促销活动时访问量会暴增,为了保证系统核心功能的稳定性和可用性,我们需要一些应对策略。这些应对策略也就是所谓的服务降级。下面根据笔者的实际经历,跟大家聊聊服务降级那些事儿。希望对大家有所启发!

服务降级方式和案例

关闭次要功能

在服务压力过大时,关闭非核心功能,避免核心功能被拖垮。

例如,电商平台基本都支持物流查询功能,而物流查询往往要依赖第三方物流公司的系统接口。物流公司的系统性能往往不会太好。所以我们经常会在双11这种大型促销活动期间把物流接口屏蔽掉,在页面上也关掉物流查询功能。这样就避免了我们自己的服务被拖垮,也保证了重要功能的正常运行。

降低一致性之读降级

对于读一致性要求不高的场景。在服务和数据库压力过大时,可以不读数据库,降级为只读缓存数据。以这种方式来减小数据库压力,提高服务的吞吐量。

例如,我们会把商品评论评价信息缓存在Redis中。在服务和数据库压力过大时,只读缓存中的评论评价数据,不在缓存中的数据不展示给用户。当然评论评价这种不是很重要的数据可以考虑用NOSQL数据库存储,不过我们曾经确实用Mysql数据库存储过评论评价数据。

降低一致性之写入降级

在服务压力过大时,可以将同步调用改为异步消息队列方式,来减小服务压力并提高吞吐量。既然把同步改成了异步也就意味着降低了数据一致性,保证数据最终一致即可。

例如,秒杀场景瞬间生成订单量很高。我们可以采取异步批量写数据库的方式,来减少数据库访问频次,进而降低数据库的写入压力。详细步骤:后端服务接到下单请求,直接放进消息队列,消费端服务取出订单消息后,先将订单信息写入Redis,每隔100ms或者积攒100条订单,批量写入数据库一次。前端页面下单后定时向后端拉取订单信息,获取到订单信息后跳转到支付页面。用这种异步批量写入数据库的方式大幅减少了数据库写入频次,从而明显降低了订单数据库写入压力。不过,因为订单是异步写入数据库的,就会存在数据库订单和相应库存数据暂时不一致的情况,以及用户下单后不能及时查到订单的情况。因为是降级方案,可以适当降低用户体验,所以我们保证数据最终一致即可。流程如下图:

屏蔽写入

很多高并发场景下,查询请求都会走缓存,这时数据库的压力主要是写入压力。所以对于某些不重要的服务,在服务和数据库压力过大时,可以关闭写入功能,只保留查询功能。这样可以明显减小数据库压力。

例如,商品的评论评价功能。为了减小压力,大促前可以关闭评论评价功能,关闭写接口,用户只能查看评论评价。而大部分查询请求走查询缓存,从而大幅减小数据库和服务的访问压力。

数据冗余

服务调用者可以冗余它所依赖服务的数据。当依赖的服务故障时,服务调用者可以直接使用冗余数据。

例如,我之前在某家自营电商公司。当时的商品服务依赖于价格服务,获取商品信息时,商品服务要调用价格服务获取商品价格。因为是自营电商,商品和SKU数量都不太多,一两万的样子。所以我们在商品服务冗余了价格数据。当价格服务故障后,商品服务还可以从自己冗余的数据中取到价格。当然这样做价格有可能不是最新的,但毕竟这是降级方案,牺牲一些数据准确性,换来系统的可用性还是很有意义的!(注:由于一个商品会有多个价格,比如普通价,会员价,促销直降价,促销满减价,所以我们把价格做成了单独的服务)

数据冗余可以结合熔断一起使用,实现自动降级。下面的熔断部分会详细说明。

熔断和Fallback

熔断是一种自动降级手段。当服务不可用时,用来避免连锁故障,雪崩效应。发生在服务调用的时候,在调用方做熔断处理。熔断的意义在于,调用方快速失败(Fail Fast),避免请求大量阻塞。并且保护被调用方

详细解释一下,假设A服务调用B服务,B发生故障后,A开启熔断:

对于调用方A:请求在A直接快速返回,快速失败,不再发送到B。 避免因为B故障,导致A的请求线程持续等待,进而导致线程池线程和CPU资源耗尽,最终导致A无法响应,甚至整条调用链故障。

对于被调用方B:熔断后,请求被A拦截,不再发送到B,B压力得到缓解,避免了仍旧存活的B被压垮,B得到了保护。

还是以电商的商品和价格服务为例。获取商品信息时,商品服务要调用价格服务获取商品价格。为了提高系统稳定性,我们要求各个服务要尽量自保。所以我们在商品服务加了熔断,当价格服务故障时,商品服务请求能够快速失败返回,保证商品服务不被拖垮,进而避免连锁故障。

看到这,可能有读者会问,快速失败后价格怎么返回呢?因为是自营电商,商品和SKU数量都不太多,一两万的样子。所以我们做了数据冗余,在商品服务冗余了价格数据。这样我们在熔断后获取价格的fallback方案就变成了从商品服务冗余的数据去取价格。下图为商品服务熔断关闭和开启的对比图。

开源熔断组件:Hystrix,Resilience4j等

限流

说起服务降级,就不可避免的要聊到限流。我们先考虑一个场景,例如电商平台要搞促销活动,我们按照预估的峰值访问量,准备了30台机器。但是活动开始后,实际参加的人数比预估的人数翻了5倍,这就远远超出了我们的服务处理能力,给后端服务、缓存、数据库等带来巨大的压力。随着访问请求的不断涌入,最终很可能造成平台系统崩溃。对于这种突发流量,我们可以通过限流来保护后端服务。因为促销活动流量来自于用户,用户的请求会先经过网关层再到后端服务,所以网关层是最合适的限流位置,如下图。

另外,考虑到用户体验问题,我们还需要相应的限流页面。当某些用户的请求被限流拦截后,把限流页面返回给用户。页面如下图。

另外一个场景,假如有一个核心服务,有几十个服务都调用他。如果其中一个服务调用者出了Bug,频繁调用这个核心服务,可能给这个核心服务造成非常大的压力,甚至导致这个核心服务无法响应。同时也会影响到调用他的几十个服务。所以每个服务也要根据自己的处理能力对调用者进行限制。

对于服务层的限流,我们一般可以利用spring AOP,以拦截器的方式做限流处理。这种做法虽然可以解决问题,但是问题也比较多。比如一个服务中有100个接口需要限流,我们就要写100个拦截器。而且限流阈值经常需要调整,又涉及到动态修改的问题。为了应对这些问题,很多公司会有专门的限流平台,新增限流接口和阈值变动可以直接在限流平台上配置。

关于限流,还有很多细节需要考虑,比如限流算法、毛刺现象等。篇幅原因,这些问题就不在本文讨论了。

开源网关组件:Nginx,Zuul,Gateway,阿里Sentinel等

服务降级总结和思考

上面我们结合具体案例解释了多种降级方式。实际上,关于服务降级的方式和策略,并没有什么定式,也没有标准可言。上面的降级方式也没有涵盖所有的情况。不同公司不同平台的做法也不完全一样。不过,所有的降级方案都要以满足业务需求为前提,都是为了提高系统的可用性,保证核心功能正常运行。

降级分类

一般我们可以把服务降级分为手动和自动两类。手动降级应用较多,可以通过开关的方式开启或关闭降级。自动降级,比如熔断和限流等属于自动降级的范畴。大多手动降级也可以做成自动的方式,可以根据各种系统指标设定合理阈值,在相应指标达到阈值上限自动开启降级。在很多场景下,由于业务过于复杂,需要参考的指标太多,自动降级实现起来难度会比较大,而且也很容易出错。所以在考虑做自动降级之前一定要充分做好评估,相应的自动降级方案也要考虑周全。

大规模分布式系统如何降级?

在大规模分布式系统中,经常会有成百上千的服务。在大促前往往会根据业务的重要程度和业务间的关系批量降级。这就需要技术和产品提前对业务和系统进行梳理,根据梳理结果确定哪些服务可以降级,哪些服务不可以降级,降级策略是什么,降级顺序怎么样。大型互联网公司基本都会有自己的降级平台,大部分降级都在平台上操作,比如手动降级开关,批量降级顺序管理,熔断阈值动态设置,限流阈值动态设置等等。

写在最后

本文的主要目的是通过具体实例,让大家了解服务降级,并提供一些降级的思路。具体的降级方式和方案还是要取决于实际的业务场景和系统状况。

OK,就分享到这。如果感觉本文对您有帮助,有劳点下在看,分享知识是美德哦????

更多干货请关注:架构师进阶之路

你可能感兴趣的文章:

《秒杀系统设计~亿级用户》

《基于微服务的互联网系统稳定性~亿级用户》

《服务化带来的数据一致问题—分布式事务,事务型消息》

《经常用Redis,这些坑你知道吗?》

《程序员进阶架构师路线》

《普通二本大学生拿下阿里Offer的真实经历》

《熔断的意义和适用场景,你真的清楚吗?》

《服务化带来的问题—之数据迁移经历》

《服务化带来的问题,我们是如何解决的》

《记一次摩拜单车JVM线程阻塞排查过程》

《JVM 频繁GC快速排查捷径》

《JVM垃圾回收实战》

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注