如何实现互联网应用的高可用性?「付钱拉」给出答案

2024-08-29
来源:网络整理

对于互联网应用以及大型企业应用来说,大多都要求尽可能实现7*24小时不间断运行,但实现完全不间断运行可以说是“极其困难”的。

为此,应用程序可用性的一般衡量标准是三到五个9。

列 1列 2列 3

可用性指标

计算方法

不可用时间(分钟)

99.9%

0.1%*60

525.6

99.99%

0.01%*60

52.56

99.999%

0.001%*60

5.256

对于一个功能和数据量不断增长的应用来说,维持一个比较高的可用性绝非易事。为了实现高可用性,富千拉在避免单点故障、保证应用本身的高可用性、解决交易量增长等问题上做了大量的探索和实践。

在不考虑外部依赖系统突发故障,如网络问题、第三方支付、银行大面积不可用等情况下,“福千拉”的服务容量可达99.999%。

本文主要讨论如何提高应用程序本身的可用性,如何避免单点故障、解决交易量增长的问题将在其他系列中讨论。

为了提高应用的可用性,首先要做的就是尽可能的避免应用故障,但完全避免故障是不可能的,互联网是一个容易发生“蝴蝶效应”的地方,任何看似概率为零的小事故都有可能发生,然后被无限放大。

大家都知道它非常稳定可靠,“福千拉”从开始就是采用单点,从来没有出现过运行故障,所以大家心理上都认为这东西不太可能出现问题。

直到有一天,这个节点所在的物理主机的硬件因为年久失修而发生故障,这时候这台主机已经无法再提供服务,导致系统服务瞬间不可用。

出现故障并不可怕,最重要的是及时发现并解决故障,富千拉要求自身系统能够秒级发现故障,快速诊断、快速解决,降低故障带来的负面影响。

首先我们来简单回顾一下遇到的一些问题:

从历史中学习

(1)新开发人员在处理新接入的三方通道时,由于经验不足,忽略了设置超时的重要性,这个小细节导致三方队列中的交易全部被阻塞,影响了其他通道的交易;

(2)“”系统采用分布式部署,支持灰度发布,环境、部署模块众多且复杂,一旦增加新模块,由于存在多个环境,且每个环境都是双节点,导致新模块上线后数据库连接数不足,影响其他模块的功能;

(3)同样由于超时问题,三方超时导致所有当前配置的事务都被耗尽,没有可用的线程来处理其他事务。

(4)甲方同时提供认证和支付接口,其中一个接口因“拉取支付”交易量突然暴增,触发了网络运营商对甲方的DDoS限制。通常数据中心的出口IP是固定的,因此网络运营商误认为从这个出口IP发出的交易是流量攻击,最终导致甲方的认证和支付接口同时不可用。

(5)再说一下数据库的另一个问题,也是因为“Pay La”的交易量突然增加导致的。创建序列的同事给某个序列设定了 999、999、999 的上限,但是数据库中这个字段的长度是 32 位。当交易量较小的时候,系统生成的值与字段的 32 位相匹配,序列就不会增加。但是随着交易量的增加,序列不知不觉地变大了,导致 32 位不够存。

此类问题在互联网系统中非常常见且隐蔽,因此避免这些问题非常重要。

下面我们从三个方面来看看《Pay to La》做出的改变。

1. 尽可能避免失败

设计容错系统

.png

比如重路由。对于用户支付来说,用户并不关心自己的钱是从哪个渠道支付的,只关心支付成功与否。「」对接了30多个渠道,有可能A渠道支付失败,这时候就需要动态重路由到B渠道或者C渠道。这样,系统重路由就可以避免用户支付失败,实现支付容错。

对于 OOM 也有容错性,比如系统内存会一直用完,如果一开始就给应用本身预留一些内存,当系统 OOM 发生时,就可以忍受这个异常,避免这次 OOM。

某些环节快速失败

快速失败原则是指,当主要流程中的任何一步出现问题时,应该快速合理地结束整个流程,而不是等到产生负面影响时才结束。

以下是一些示例:

1、启动“Pay Lare”时,需要加载一些队列信息和配置信息到缓存中,如果加载失败或者队列配置不正确,会导致请求处理失败,最好的处理方式是加载数据失败,直接退出JVM,避免后续启动不可用。

2、“Pay ”实时交易处理最大响应时间为40秒,若超过40秒,前置系统将不再等待,释放线程,并告知商户正在处理,后续处理结果以业务线通知或主动查询的方式获取;

3、“Pay ”使用缓存数据库,用于实时报警跟踪和重复验证,若连接时间超过50ms,则自动放弃操作。最坏情况下,该操作对支付的影响也只有50ms,在系统允许的范围内。

设计自我保护系统

系统一般都会有第三方的依赖,比如数据库,第三方接口等等,在开发系统的时候,需要对第三方保持怀疑态度,避免第三方出现问题时引发连锁反应,导致系统宕机。

(1)拆分消息队列

「福钱拉」为商户提供了多种支付接口,最常用的有快捷、个人网银、企业网银、退款、撤单、批量支付、批量扣款、单笔支付、单笔扣款、语音支付、余额查询、身份证认证、银行卡认证、卡密码认证等。对应的支付渠道包括微信支付、支付宝等30多个支付渠道,对接了上百家商户。在这三个维度上,如何保证不同的业务、第三方、商户、支付类型之间互相不影响,「福钱拉」做的就是对消息队列进行拆分。下图是部分业务消息队列的拆分图:

.png

(2)限制资源的使用

资源使用限制的设计是高可用系统最重要的一点,但也容易被忽视。资源是相对有限的,过度使用自然会导致应用宕机。为此,「付钱」做了以下功课:

架构支付系统包括_支付系统架构_支付系统架构设计

分布式水平扩展需要考虑数据库连接数,而不是无止境地最大化,数据库连接数是有限的,需要全局考虑所有模块,特别是水平扩展带来的增量。

内存占用过高会导致频繁GC、OOM。内存占用主要来自以下两个方面:

1.收集容量太大;

2.不再被引用的对象不会被释放。比如put进去的对象会被回收,直到线程退出。

无限制的创建线程最终导致线程不可控,尤其是隐藏在代码中的线程创建方法。

当系统的SY值过高时,意味着线程切换需要花费较多的时间。Java中产生这种现象的主要原因是因为创建了较多的线程,而这些线程不断的处于阻塞状态(锁等待、IO等待)和执行状态改变,从而产生了大量的上下文切换。

另外Java应用程序在创建线程时都是操作JVM堆之外的物理内存,过多的线程会占用过多的物理内存。

最好通过线程池来创建线程,避免线程过多造成上下文切换。

做过支付系统的应该都知道,有些第三方支付公司对商户的并发是有要求的,第三方支付公司允许的并发数是根据实际交易量来评估的,所以如果不控制并发,把所有交易都发给第三方支付公司,第三方支付公司只会回复“请降低提交频率”。

因此在系统设计和编码阶段都要特别注意将并发度限制在三方允许的范围内。

我们讲了《Pay 》为了实现系统可用性所做的三点改变,第一点就是尽量避免故障,接下来我们讲最后两点。

2.及时发现故障

故障犹如日寇入寨,来得猝不及防。当第一道防线被突破后,如何及时设置第二道防线,发现故障,保证可用性,是报警监控系统的关键。没有仪表盘的汽车,无法知道车速、油量,转向灯是否打开,即使是经验丰富的司机,也非常危险。同样,系统也需要监控,最好在危险发生时提前发出警报,这样在故障真正造成风险之前,就能解决问题。

实时报警系统

如果没有实时报警,系统运行状态的不确定性将造成无法量化的灾害。“佩拉”的监测系统指标如下:

告警主要分为单机告警和集群告警,而“拉拉支付”属于集群部署。实时预警主要通过对各个业务系统的实时数据点进行统计分析来实现,因此难点主要在数据点和分析系统上。

隐藏的数据

为了实现实时分析,又不影响交易系统响应时间,“福千拉”在系统各个模块实时采集数据,然后将采集到的数据汇总到分析系统中,分析系统依据规则进行分析、报警。

分析系统

分析体系最难的就是业务报警点,比如哪些报警一发出来就要立即响应,哪些报警只要一发出来就只需要关注。下面我们对分析体系进行详细的介绍:

1.系统运行架构

.png

2.系统运行流程

.png

3.系统业务监控点

“福千拉”的业务监控点都是在日常运营过程中一点一滴总结出来的,分为报警和注意两大类。

警务调度类别:

4. 非营业性监测点

非业务监控点主要是指从运维角度的监控,包括网络、主机、存储、日志等,具体如下:

使用JVM收集GC/Full GC次数及次数、堆内存、耗时线程堆栈、缓存长度等信息。

在各个服务器上部署监控代理,实时收集流量信息。

采用间歇检测的方式,观察三方或者网络是否稳定。

对于MQ消费队列,使用脚本检测实时分析队列深度;

数据库部分,安装插件xdb,可以实时监控数据库性能;

通过完成分布式日志的采集,再经过系统的分析处理,完成日志的实时监控和分析,最后开发出可视化的页面展示给用户。

通过监控主机的CPU负载、内存使用率、各网卡的上下行流量、各磁盘的读写速率、各磁盘的读写次数(IOPS)、各磁盘的空间使用率等。

以上就是“福千拉”实时监控系统做的事情,主要分为业务点监控和运维监控两个方面,虽然系统是分布式部署的,但是每个预警点都是秒级响应的。另外,业务系统的报警点也有一个难点,就是有些报警量少不一定有问题,量大了就会有问题,也就是所谓的量变导致质变。

例如,如果出现一次网络异常,可能是由于网络抖动导致的,但如果出现多次异常,则需要关注网络是否真的存在问题。针对网络异常“Pay and pull”的告警示例如下:

记录分析系统

对于一个大型系统来说,每天记录和分析大量的日志是非常困难的,福千拉平均每天有200万的订单,一笔交易要经过十几个模块,假设一个订单记录30条日志,可以想象每天的日志量会有多庞大。

“福千拉”日志的分析有两个作用,一是提供实时日志异常预警,二是提供订单轨迹供运营人员使用。

实时日志警告

实时日志预警是针对所有实时事务日志,用 or 关键字实时抓取然后报警。这样做的好处是如果代码出现异常,可以立刻发现。「福千拉」处理实时日志预警的方式是先完成日志采集,然后通过分析系统实时抓取,再实时预警。

订单追踪

对于交易系统来说,实时了解订单状态是非常必要的。“福钱拉”最初的做法是通过数据库记录订单轨迹,但运行一段时间后发现,订单量的剧增导致数据库表过于庞大,难以维护。

“福千拉”目前的做法是各个模块打印日志轨迹,日志轨迹打印格式以数据库表结构的形式打印。所有日志打印完成后,日志采集就完成了。分析系统会实时抓取打印的标准化日志,进行解析,然后按日存入数据库,并以可视化的界面展示给操作员。

日志打印规范如下:

2016-07-22 18:15:00.512||pool-73--4||通道适配器||通道适配器-发送给三方后|||||||||||04||9000||【结算平台消息】处理中||||||GHT||03||11||2016-07-22 18:15:00.512||张张|||||01||||true||||||||10.100.140.101||-0d01-4ed4-b771-||10.999.140.101||O001||||0.01|||||||||:8080//||||240||2016-07-20 19时06分13秒。

分享