此文已由作者王文学授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
网易宝支撑了整个集团业务绝大部分的支付场景,平均每天的支付订单有100万单,接近1亿的交易额。对系统的可用性要求极高。下面就从我的理解上说说网易宝的系统是如何实现高可用的。
1. 网易宝系统的整体架构
先看看网易宝的系统整体架构(16年初的架构)
网易宝目前系统整体架构图
中间大的浅蓝色的部分为网易宝系统的整个体系。按照从下到上的层次关系分为存储层、技术组件、服务层、接入层。每个层都有系统监控来监控系统的状态。服务层和接入层有风控系统来监控风险行为,保障用户资金的安全。
存储层:数据库主要使用Oracle。网易宝的核心支付服务是基于本地事务去保证数据强一致性的。用户支付完成,订单状态修改为成功,扣除余额,产生资金流水,需要强一致性的保证。订单和流水的数据占了网易宝数据库业务数据的绝大部分。Oracle在单机大表的性能上是非常高的。所以数据库采用的Oracle。文件存储主要使用的FTP。用于存放银行清算文件、对账文件、结算文件。
技术组件层:包括dubbo分布式远程调用中间件、消息队列中间件kafka、 分布式应用程序协调服务Zookeeper、分布式缓存存储memcached、杭研调度系统、linux-crontab(逐步迁移到杭研调度系统上,后续废弃)
服务层:为网易宝的核心层,提供高内聚的服务。网易宝支持多样化的支付需求是通过组装服务层的服务来完成业务流程的。包括用户账户服务,订单查询服务,支付核心服务(实现了实名,绑卡,充值,支付,提现,退款的核心流程);网关服务payments-trans接入了几十家银行和其他支付通道;积分服务提供积分红包的充值、提现、发放和消费服务;网关路由服务gate-service提供支付时路由到具体的支付通道的服务;sign-service提供签名服务,保证内部系统之间和外部系统的调用请求的安全性;pay-gate提供第三方支付通道的对接服务;platform-module提供商户数据的查询服务。接入服务层的服务的方式包括dubbo,http,依赖jar组件。对账中心和结算中心不参与用户支付的流程,对账中心支持所有银行通道的对账,核对我们的备付金和用户商户的账户资金完全无误, 对网易宝的资金流水按会计分录做到日切,符合人行的监管要求。结算中心给商户提供人民币结算服务和外币结算服务。
接入层: 分为前台系统(界面交互, 后台API接口)和管理后台系统。 前台系统包括用户前台epay-web、收银台cashier(从epay-web拆分出来,正在开发中)、网易宝用户端APP、可嵌入第三方APP的支付SDK组件、活动系统promotion、商户前台系统platform-web。 管理后台系统包括后台管理epay-admin、网关管理payments-admin、商户后台管理platform-boss(正在开发中)。
风控: 对用户在网易宝的整个行为做风险控制,保障用户账号和资金的安全。风控通过kafka异步方式同步网易宝的业务数据,运用大数据处理技术做分析。
与网易宝接入层人机交互的有用户、商户、后台管理人员(技术支持&客服&财务),商户的应用(游戏、 考拉、一元夺宝、邮箱、理财等)。
网关系统和对账中心后台依赖几十家银行的网关。
以上对网易宝的整个体系架构按照层次做了个简单的介绍,下面进入主题,网易宝系统是怎么实现整体系统的高可用性的。
2. 系统高可用性的分析
2.1 集群部署、负载均衡、备份(消除单点问题)
网易宝的所有核心应用和中间件都是集群部署的,通过负载均衡,平均分配流量。
对于业务系统, 在nginx服务器(nginx集群部署,负载均衡使用LVS)上配置了负载均衡策略,路由请求到后端的应用服务器resin。如果web应用集群某台机器挂了,nginx通过心跳健康检查,3秒内能检测到,把这台机器从可用列表中剔除出去。
中间件dubbo的consumer基于负载均衡算法, 获取zookeeper上统计的provider的负载情况,决定请求哪台provider。Kafka也是类似的原理。如果dubbo服务的某台provider挂了,与provider维持长连接的zookeeper心跳线程会检测到,把provider从服务的可用provider列表中剔除,并快速通知到所有依赖该服务的consumer(也是维持的TCP长连接),consumer更新本地缓存的provider列表。
对于有状态的服务器,都有数据备份机制。
数据库主库会异步同步数据到备库。数据库主库挂了,如果切到备库,可能会丢失部分业务数据(异步复制,网络稳定情况下10ms以内的延迟,不是同步写多份的)。Kafka每条消息都会复制到不同的机器(broker)上。Zookeeper上的数据也是多写的。Kafka的主broker挂了或者zookeeper的主服务器挂了,通过选举算法选举出新的leader。Leader用于读写,slavers用于备份。Leader挂了,从slavers中选举出新的leader快速恢复服务。Kafka和zookeeper是做了数据高可靠性保证的,极小概率会出现丢失数据的情况。
多机房部署上,网易宝有杭州、北京两地机房。杭州是主机房,北京是备,不是多活的。 北京的机房服务器数量较少,数据库服务器性能较差,数据复制也有秒级的延迟。所以不到万不得已,是不会切到备用机房的。目前网易支付已经在搭建义桥的机房,2017年实现滨江机房和义桥机房的双活,解决机房的单点问题。
综上所述,在同一个机房,网易宝无论是无状态的服务器,还是有状态的服务器,从存储层,到中间件层,到应用层,都不存在单点问题。机房的单点问题也会在不久后解决。
2.2 缓存:空间换时间
更新不频繁的基础热点数据,如配置项、所有商户信息、网关数据,在应用启动时,加载到本地缓存。减少对数据库的频繁调用。
2.3 应用无状态化,支持横向扩展
网易宝的session管理使用中心化的memcached集群,业务流程中的一些状态数据,也是存放到memcached。系统之间使用文件数据交互的,文件保存到FTP。需要持久化的业务数据保存到中心化的数据库。 不管是业务数据,还是非业务数据,都不会保存到本地应用服务器,保证应用无状态化,使得应用集群可以快速的横向扩展。
2.4 读写分离
为了保证核心支付服务的稳定性,数据库上做了读写分离。核心业务的读写走主库。对于读实时性要求不高的查询场景,查询备库。如商户系统订单的查询请求。对于耗时长的sql的查询场景,查询异构库,如商户的对账单下载。
2.5 异步化
热点账户处理异步化
为了避免热点账户上的行锁的激烈竞争影响系统吞吐,网易宝对热点账户的余额更新和资金流水生成,做了异步处理。业务完成后如果需要变动热点账户的金额,先生成缓冲流水,然后由调度任务异步去消费缓冲流水去更新余额、生成资金流水。使热点账户的并发锁竞争变成了串行处理,大大降低了行锁竞争导致的线程阻塞,提高了系统的吞吐。
提现、退款处理异步化
提现、退款处理对实时性的要求不高,通过异步化,对于处理失败的订单可以用重试机制补偿。避免了同步调用失败给用户不好的体验。
2.6 系统拆分解耦、核心代码多版本归一
早期的网易宝只包括epay、epay-admin、payments、sign几个系统。 大部分的业务功能都集中在epay一个应用里。epay应用非常的庞大,包含了用户前台、收银台、积分红包、活动、商户前台功能、API、风控、资金对账监控。存在以下几个问题:
a.核心业务功能和非核心业务功能在一个系统里,代码紧耦合,并且公用服务器资源,非核心业务功能出现问题容易影响到核心业务功能。
b.在一个应用上大量的分支并行开发feature,合并代码容易冲突。应用的一次发布包含几十个feature。一个feafure发布出问题,发布回滚,导致其他feature也一起回滚了。造成开发效率和发布效率低。
c.epay系统经过几年的业务和技术选型升级,遗留下代码多套并存的问题。一个需求的变更,可能需要从上层到下层,改动多套代码。核心代码的多套并存、低内聚,代码难以维护,使开发的工作量变大,并且容易出bug。使后续的系统拆分,服务化改造困难重重。
为了提高系统的整体可用性,提高大家的工作效率,针对以上几个问题,网易宝在过去的一两年里做了很多的重构改造工作。包括以下几个方面:
2.6.1 系统拆分
积分红包底层service从epay中拆分出来,独立jifen系统,提供服务化的接口。
活动功能从epay中拆分出来,独立promotion系统,提供活动业务功能。
风控模块从epay中拆分出来,独立risk系统,提供限额服务、黑白名单服务、反洗钱监控、用户风险评级。
网关路由模块从epay中拆分出来,独立gate-service系统,提供网关查询和路由支付、提现通道的高可用服务。
Epay与网关路由服务的调用关系
商户前台系统从epay中拆分出来,独立platform-web系统,提供商户的业务功能。
商户系统模块依赖关系图
2.6.2 代码重构
底层核心代码消除多个版本,统一为一个版本实现,内聚化。
epay核心代码内聚归一
epay按层次拆分为多个子工程,底层子工程可以打包为公共jar组件,也可以包装为服务化接口。
Epay子工程拆分依赖关系图
3. 总结
提高系统的可用性非一蹴而就,只有深入的理解业务,梳理清楚业务流程和依赖关系,工作中不断的发现系统的痛点,逐个解决,步步为营,系统的整体可用性才能上一个台阶。
网易云免费体验馆,0成本体验20+款云产品!
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 JVM锁实现探究2:synchronized深探