🪂 兜底和容灾
!本篇文章过于久远,其中观点和内容可能已经不准确,请见谅!~
想分享的是对于网络层可用性的一些常见端侧优化案~~
明天和意外哪个先来临?
没有人能说自己手中的项目能够万无一失,没人能保证千万分之一的错误率,不能被你遇到,程序崩溃,服务瘫痪的例子已经不算是新闻了,一个大型项目的上线,怎么才能保证健壮和稳定呢?
从源头考虑,比较基础的有代码规范、强类型限制、MergeRequest、代码静态检查等等,能够避免一开始的编码问题,这里不多说,因为你足够小心就不会让意外出现在用户手中。
哪怕再小心,很多意外也是没办法解决,涉及到很重要的体验问题,还是需要你准备一套 PLAN B 的。
对于可用的兜底处理,基本上会出现两个极端:
- 几乎不考虑兜底,只要完成任务即可。结果体验问题的反馈很多,一点点找补。
- 太考虑兜底,多级缓存,多层复用,导致技术架构复杂,维护困难。
并没有说哪个不好,问题的关键就是怎么把握这个度。大流量的业务,兜底必须做足,小流量的业务,可能还没来得及思考就下线了。
比如用户拉取首页数据,网络高峰期,导致请求响应超时或者错误,怎么处理?类似这种情形都是与业务无关,但是仍然需要客户端额外处理。
比如服务器没有做分布式,偏远地区、服务器宕机或者解析波动导致网络很容易超时,不可能一致 Loading 下去,乃至 try catch 到,导致没有数据填充,界面白屏。
有些开发从自身这块的处理多思考了一些,会将错误显示出来,但是直白的将网络状态或者错误码呈现给用户,401、504等等错误码,但是用户仍然一脸懵。
治本的解决方案是增加服务能力,降低网络波动的概率,不过这里我们讨论的更多是策略上怎么优化这个体验:
以下的方法仅讨论端侧网络的方案,基本上都是封装到网络层的实现。
- 自动重试根据我们的业务实践中,大部分都是网络错误问题,导致界面异常或者崩溃,这其中大部分能够使用二次重试解决问题。虽然这个重试低成本,但是尤其需要注意他的实现逻辑,严格排除那些不能重试的业务,多次重试一定要控制次数,避免循环重试给自己的服务器来一次 DDoS 攻击。
- 自动修复在相对底层的地方封装一些错误检测和修复方法,对于比如网络劫持、代理、证书问题等,提供检测、提示和修复的能力。出现网络劫持就升级 https,升级 https 之后出现证书问题,证书校验还可能会有网络问题,这里面很多想不到的异常需要收集和解决。
- 负载均衡和自动故障转移分布式架构、多服务中心、就近服务等,服务端有很多的策略让端侧的性能有更好的稳定性。但是在端侧也可以主动做一些体验优化,比如定时向多个服务中心测试网络情况,根据初始测量结果来决策主备网关。服务端的策略更多是针对地区性的性能优化,但是对于端侧来说并不一定是最优的网关跳转。从端侧来做方案,可以相对个性化的优化网络方案。但是端侧策略可能会无法平衡负载,可能导致服务器的负载策略被端侧被打破。
- 备用接口分布式架构、多服务中心、就近服务等方案都属于传统意义上的同一个接口的负载均衡,但是除此之外,还有多接口均衡的策略。比如首页用户列表接口,平时是用的个性化排序,但是业务高峰期,个性化的性能压力太大,接口速度明显变慢,甚至接口出现问题,那么就可以稍微做一些降级策略,将个性化排序的接口替换为普通排序接口。这种方法还能屏蔽后台服务中个性推荐部分出现的逻辑问题。当然这些前提是你切换到的备用接口的承载能力必须能够 hold 住这些流量。最差的情况是做一个静态接口,每日或者每时更新一个基础接口返回值,乃至最差的手写一个示例数据,在动态化完全不可用的时候,将流量都切到纯静态的接口,至少满足暂时的服务器重启时间。
- 数据缓存和 api sw上一次的请求缓存到本地,这次网络请求如果出现问题,可以在权衡数据有效性之后显示缓存的内容,至少比 loading 要有意义的多。不过需要一些不太变化的数据,并且设置过期时间。web 端的 sw 可以作为 API 的中转站,来处理请求缓存,平滑处理一些网络不稳定的情况。
- 有意义 ssr 和 site sw对于前端,用户每一个网络请求都是有代价的,ssr 出一个页面或者实现渲染出主要内容区,相比空白页面很多的骨架 loading 在请求多个接口填内容要好的多。前端来说整站的 sw 也是一种很好的网络缓存,将整个站点通过 SW 来实现离线化访问,满足哪怕视觉上的一点焦虑缓解。
以上的能力都需要通过工程化的手段封装在网络层,而且在用户量不大的时候选择性的上。
使用分布式网关降低网络请求集中导致的网络问题,事先填充上次数据缓解等待情绪,网络返回出现问题后检测网络状态,断网提示,未断网重试,重试错误后更换备用接口,再失败后提示网络问题,提供重试按钮甚至网络诊断工具。
对业务的可用性支持有很多手段,目的都是在最坏的情况下让业务满足基本的可用。
这部分是客户端对网络接口层的检测反馈机制。但是实现比较完备及时的一套机制,需要依靠体系,比如整个应用的埋点、大数据平台搭建、告警规则和推送,这里东西搭建起来之后,一个接口监测自然就是顺带的了。
最后想多说一些“可用性”(Availability)这三个字的思考。
通过各种方法,尽力让整个系统正常运行,为了保证核心业务场景的可用,宁愿牺牲掉一些边界业务。
解决“不可用性”的流程,梳理可能出现不可用的断点,把每个不可用的地方都进行多层优化。
假设一个界面,可用性取决于:“服务接口”、“网关”、“物理链路”、“网络波动”、“本机接收”几个环节,每个环节都有极端的 10% 错误率,那么如果不做优化的情况,可用性最终只有
90%*90%*90%*90%*90% = 66.2% 的大小。但是其中每个环节都只提供一个备用方案,那么每个环节的错误率能降低到
10%*10% = 1% ,那么整个环节的可用率能很轻松的提高到:99%*99%*99%*99%*99% = 95% 。所以每个薄弱的环节,兜底一层就能将整个业务的可用性提高到非常好的程度,很划算。
上面的再试一次或者备用方案,说到底都是统计意义上的优化可用性,错误就是错误,不能因为再试一次成功了就不是错误了。仍然是问题,可能是认为不可控的问题,可能是方案考虑不周,甚至可能是软件 BUG,这都是需要解决和处理掉的。
所以将错误行为自动诊断出来,针对不同的诊断施行不同的兜底方案来排故才是精准手术。
最简单的“麦克风录制”可能出现的问题有:没有设备、没有权限、没给权限、设备被占用、设备无法读取、安全错误、无法编码、存储无权限、存储被占用、存储安全问题、存储无法写入等等,里面很多事无法解决的,但是仍然需要根绝这些不同的错误采取不同的策略来重试,自动排除这些故障。
为了完美的业务体验,很多的场景都是有要求的,比如个性化推荐的千人千面,比如实时结算和扣款,比如聊天消息的实时推送,比如视频的高清等等业务,他们都并不是没有代价的,效果好坏都取决于相应的计算资源和时间。
在业务高峰期,我们的服务资源是很有限的,可用性要远比这些“更好的体验”重要。
所以我们需要主动对业务降级,将好的替成相对没那么好的,节省资源来拉高可用性。比如推荐没那么关联的商品、比如稍微异步排队的结算和推送、比如相对低清晰度的视频资源。
甚至还可以对部分目标用户或者非核心请求进行限流,甚至根据可用性状态,主动对边缘业务熔断等策略,放弃一部分业务,来保全可用性。
这篇文章的出发点,是在端侧搭建一套网络层的时候,结合实际流量对业务可用性的思考。
根据这些想法,在
req 和 res 之间搭建非常好玩的异常优化策略,把可用性做上来,过程很有意思。感谢您的阅读,本文由 Ubug 版权所有。如若转载,请注明出处:Ubug(https://ubug.io/blog/fallback)