文章目录
1 有关架构的概念认知
规划、架构、设计
- 以解耦为基础考虑服务化,遵循单一职责,松耦合意味着可以独立更新这些服务
如何做架构设计
- 以终为始,用户的本质需求(体验/响应时间,准确性)
- 是否要考虑链路级的监控,以及链路级的关键数据校验;
- 如果规则分散到多个系统,如何检查整体组合的命中等情况;
- 链路上每个系统的容量和响应时间是多少;
- 抽象、协作、扩展、复用
- 分析全息视图
- 架构兼具组成和决策的特点
- 如何对软件系统进行组织
- 如何选择组成系统的结构元素和它们之间的接口,以及如何设计当这些元素相互协作时所体现的行为
- 如何组合这些元素,使它们逐渐合成更大的子系统
- 软件架构并不仅仅注重软件本身的结构和行为,还注重其他特性:使用、功能性、性能、弹性、重用、可理解性、经济和技术的限制与权衡,以及美学
- 架构是演进来的
- 任何一个选择都需要考虑投资回报率(ROI)
- 偿还技术债务、重构和不断抽象、分解问题域是演进的一些手段,保持架构演进要特别持续关注质量并保障其没有下降
3 闭环架构方法
系统提升的一般性方法和反馈环
- The Principles Underpinning DevOps
- 原理一:系统思考(System Thinking)
- 原理二:强化反馈环(Amplify Feedback Loop)
- 原理三:持续试验和学习的文化(Culture of Continual Experimentation And Learning)
- 技术研发型组织(尤其是领导层)要从全局视角审视整个IT价值流,改善瓶颈和短板,强化系统内外的反馈环,鼓励试错和试验文化,让价值在整个系统内更快、更好、更平滑地流动
- 在构建闭环反馈进行系统提升方面,普遍存在如下两个组织上的问题
- 反馈环不封闭。因为没有构建有效的数据收集、分析和监控体系,所以就没有反馈数据,决策主要依靠猜测//拍脑袋来做。另外,组织部门之间如果有严重的隔阂,缺乏信任和沟通,也容易造成反馈环不封闭
- 反馈比较慢,或者说迟反馈。客户报告了严重的Bug,但是系统从修复到再上线需要花费几周甚至更长的时间。迟反馈会让客户和股东蒙受损失,有时还是灾难性的
产品创新闭环
- 持续规模化产品创新的概念模型——基于OODA(Observe、Orient、Decide、Act)环的持续交付
- 观察(Observe):表示观察现状以发现潜在的创新点。Netflix鼓励员工勇于创新,任何人发现机会都可以发起项目进行创新研究
- 判断(Orient):表示通过分析测量数据来理解之前观察到的现象的背后原因。这通常涉及对大量数据的分析(例如日志文件分析)
- 决策(Decide):指的是开发和执行一个项目计划。公司文化对于决策有着重要的影响。Netflix的公司文化鼓励自由和责任,员工将计划公开分享,不需要层层管理审批就能主动发起项目变更
- 行动(Act):指的是测试解决方案并将其部署到生产环境。将包含增量功能的微服务发布到云环境,并开启A/B测试和之前版本做比对,基于数据判断新版本是否解决了老版本中的问题
- 基于数据的闭环反馈是OODA环的核心:如果你的每一步行动都是基于充分的数据测量做出的,而你的竞争对手主要靠需要好几个月才能验证的猜测,那么你想不赢都难
组织闭环
- 最常见的是严格职能型组织架构。严格职能型组织很容易产生孤岛效应,或者说竖井效应。每个职能团队都想成为舞台中央的明星团队,各团队容易各自为政和局部优化,所以严格职能型组织有沟通开销大、研发流程缓慢和反馈效率低下的问题
- 有一些公司会更进一步组建所谓基于产品线的跨职能团队,负责整个端到端的研发活动。跨职能团队有助于提升效率并强化反馈环,这也是国内外主流互联网公司采用的组织模型。但只要团队基于单块(monolithic)应用的开发和交付模式,就难免产生跨团队间的移交、沟通和协调活动,整体效率仍然受限。
- Netflix采用的基于微服务和PaaS平台的DevOps组织模型。跨职能的产品团队基于可独立开发、测试和部署的微服务而组建,支持端到端的研发活动;平台团队则在AWS云的基础上提供PaaS基础服务平台,将微服务基础设施、发布和监控等基础能力封装在平台内,支持开发团队进行微服务的自助式(self-service)部署。这个组织模型减少了组织间的孤岛,强化了团队内的反馈闭环,最大化了研发和交付的效率。当然,这个组织模型对技术能力和基础设施的要求更高,需要微服务架构体系、自动化部署和PaaS平台等技术手段的支撑
研发流程闭环
- 敏捷的本质是关于反馈的,不管采用哪种方法和实践,其核心都是强化反馈闭环
系统架构闭环
- 系统架构层面的闭环主要体现在系统监控方面:系统层监控,应用层监控,业务层监控
- 通过在每一层构建监控和大数据分析等闭环反馈机制,整个系统可以在反馈数据的基础上不断优化和改进
4 复杂与架构演进的关系
什么是复杂
- 规模
- 软件复杂度会受到需求与规模的正向影响,但增长趋势更加陡峭
- 需求的变化,知识的流逝,正是遗留系统之殇
- sonar 重复代码 / 其他软件复杂度或质量评估工具
- 结构
- 我们需要满足高性能、高并发的需求,就需要考虑在系统中引入缓存、并行处理、CDN、异步消息以及支持分区的可伸缩结构
- 我们需要支持对海量数据的高效分析,就得考虑这些海量的数据该如何分布存储,并如何有效地利用各个节点的内存与CPU资源执行运算
- 康威定律:任何组织在设计一套系统(广义概念上的系统)时,所交付的设计方案在结构上都与该组织的沟通结构保持一致
- 变化
- 从需求的角度讲,变化可能来自业务需求,也可能来自质量属性,而以对系统架构的影响而言,尤以后者为甚,因为它可能牵涉整个基础架构的变更
用架构思维控制复杂
- 分而治之,控制规模
- 保持架构的清晰与一致
- 合理的职责分配,良好的封装与抽象,并在约束的指导下为架构建立一致的风格
- 拥抱变化
- 与变化有关的质量属性
- 可进化性(Evolvability)
- 可扩展性(Extensibility)
- 识别软件系统中的变化点:业务规则、算法策略、外部服务、硬件支持、命令请求、协议标准、数据格式、业务流程、系统配置、界面表现
- 处理这些变化点的核心就是“封装”,通过隐藏细节、引入间接等方式来隔离变化、降低耦合
- 可定制性(Customizability)
- 在SaaS风格的系统架构中,常常通过引入元数据(Metadata)来支持系统的可定制
- 插件模式也是满足可定制性的常见做法,它通过提供统一的插件接口,使得用户可以在系统之外按照指定接口编写插件来扩展定制化的功能
- 保证组件满足自治的四要素
- 最小完备
- 稳定空间
- 自我履行
- 独立进化
- 与变化有关的质量属性
5 架构师的核心能力
职责
- 业务架构师(进行系统分析、建模以及业务架构设计)
- 技术专项领域架构师(业务领域专家、业务顾问,可以洞察行业发展)
- 技术架构师(技术专家,从事技术架构设计)
- 企业总体架构师(从事企业总体架构的规划和设计)
- 项目层面的技术架构师(Java架构师、.NET架构师)
- 方案架构师
核心能力
- 经验:坑
- 深入思考能力,时常对专题领域进行思考总结,提升判断和分析能力
- 沟通
- 商业头脑
- 快速学习,知识面广
- 保持好奇心和阅读习惯,坚持做笔记
- 深入思考问题背后的根源,学习并掌握原理和方法论
- 经常与人交流,查看知名博主的博客
- 经常总结并分类管理与分享
- 解决问题的能力
- 要不要做(是否与长期IT规划相匹配)
- 应该由谁来做(涉及系统边界问题)
- 如何做(涉及技术栈选择、方案设计等)
- 什么时候做合适(变更的关联分析)
- 如果做了,那么对将来有什么影响(跳出当前局限,站在未来的角度考虑可能有哪些变更,哪些需要当前做兼容设计)
- 做技术容易先入为主,会觉得技术的重要程度排在第一位
- 架构师应该在不同的场景内跳入、逃出,着眼大格局,从细节入手,并时时总结,尽量规避先入为主的执行思维
修炼
- 多想(“学而不思则罔”,运用计算机思维,深入思考问题背后的根源和关联问题的渊源)
- 多看(空杯心态,“他山之石,可以攻玉”,避免重复造轮子)
- 多读(“思而不学则殆”,读书而有益,多读而博知)
- 多写(学以致用,反复思考,构建知识体系)
- 多练(“绝知此事要躬行”,不自欺、不欺人、不被欺)
- 多问(不耻下问,不怕傻问题,对问题及时反思,多视角看待事物)
- 多实践(行胜于言,实践出真知,要有精益求精的工匠精神)
解决问题时的经验
- 问题描述。准确了解问题是什么,基于具体事实进行陈述,尽量详细不笼统,并以分析问题为重点进行问题信息收集(而非一些过往经验的论断)
- 分析问题(根据问题树排查)。分析问题时要简单有效、逻辑清晰,如果暂时无法确认问题,最好能给出确认问题的截止时间
- 问题跟踪分析,去掉非关键问题(通过使用漏斗法去掉非关键问题)。使用80/20的思考方式,推敲问题现象与假设间的逻辑关系,尽量做到全面考虑、避免遗漏。制订详细的工作计划,发挥团队协作的作用,让业务线相关人员尽可能参与其中(这样可能会加快问题确认的速度)。如果问题复杂,需要团队协同,则组织者要做好工作规划
- 进行关键分析。以数据为基础(避免以经验先入为主);争取得到专家的支持(充分利用他人经验);使用80/20的思考方式;经常回顾问题的目标以及论证的逻辑关系(奥卡姆剃刀定律:如无必要,勿增实体);不拘泥于现状,寻求突破性观点
- 综合调查结果,并构建论证。整合各种分析内容,串联成合乎逻辑又具有说服力的故事;关心汇报对象的关注点,做到重点突出,条理清晰;描述问题时要为关键决策者提供必要依据;根据汇报对象的不同,采用不同的方式描述问题
- 问题处理。注意紧急解决问题和完美解决问题的权衡,分析问题解决过程可能带来的影响并制订对策
- 问题解决确认。与问题提出者确认,与问题周边影响者确认,根据监控系统数据进行确认
- 知识积累。将问题记录成文件或放入知识库,并分享解决问题的过程和经验
7 微服务架构下的事务处理
可靠事件模式
业务补偿模式
- 补偿模式使用一个额外的协调服务(补偿框架)来协调各个需要保证一致性的微服务,协调服务按顺序调用各个微服务,如果某个微服务调用异常(包括业务异常和技术异常),则取消之前所有已经调用成功的微服务
- 为了降低开发的复杂性和提高效率,将协调服务实现为一个通用的补偿框架。补偿框架提供服务编排和自动完成补偿的功能
TCC(Try-Confirm-Cancel)模式
10 基于云的微服务架构
服务健康状态
发布管理
- 容量规划。通过测试报告评估应用的类型是I/O密集型、CPU密集型还是混合型,根据应用的类型申请合理的硬件资源
- 冗余规划
- 发布控制
12 如何搭建高可伸缩的移动电商架构(黄哲铿)
应对电商大促峰值的“独孤九剑”
- 大促的系统预案
- 大促开始的前几天,关闭程序发布窗口
- 通过压测来识别系统瓶颈(提前一个月做)
- 服务降级策略
- 带宽预估和报备
- 第三方接口调用量预估和报备
- 提前几天开启混合云资源
- 备用几十台服务器,以应对突发情况
- 24小时轮值
13 消费信贷系统是如何持续优化的(王辉)
大促期间的性能保证
- 异步化处理流程,减少同步等待时间,缓解高峰期压力
- 异步、缓存、多线程、业务流程优化
对消费服务进行解耦,采取“一致性实时监控服务”策略保证数据最终一致性
大促期间的稳定性保证
- 可控。我们针对系统依赖、异步化、合并请求、API隔离、慢SQL等方面进行了梳理和优化,且将API分成PC类、无线调用类和微服务类,根据这3类区分监控大盘
- 柔性
- 限流
- 降级
- 预案降级、限流降级和人工配置降级
- 预案降级,在大促快要到来之时,开始降低日志级别、定时任务脚本等一些可以短暂暂停的任务
- 限流降级,某些接口访问量异常、不在整体规划中的时候,可以使用限流来限制访问量,当达到限流阈值时,后续请求会被降级
- 人工配置降级,前期我们会梳理分清可降级功能与不可降级功能,在可降级功能处放置可降级开关
- 隔离
- 数据库隔离主要从业务维度进行划分
- 功能隔离从核心功能和非核心功能进行划分,优先保障支付链路的稳定性
- 应急预案
14 美丽联合集团支付系统架构演进(陈宗)
支付系统1.0
- 面向业务的收银台模块、支付模块,面向资金端的账务模块,以及与第三方支付对接的渠道网关
- PHP单体
业务问题
随着业务越来越复杂,添加了越来越多的支付交易表,烟囱型架构。增加一个业务便增加1~N张表
整个支付系统存在着数十个支付交易表。这么多表,侧面反映了对支付业务并没有做模型的抽象,只是在业务的野蛮生长下不断地应对和接入。同时,业务的边界很模糊,经常有业务出现这种情况:一半的业务逻辑实现在业务方,一半的业务逻辑实现在支付系统
系统问题
- 各模块耦合
- 几十个开发同时维护一个单体,稳定性非常低
- 性能瓶颈(垂直拆分、增加缓存、硬件,只能支持1800QPS的支付,目标是2000QPS)
鉴权问题
- 对各个业务方的支付接入并未提供任何授权和鉴权,对业务方接入来说确实很方便,但其实埋下了很多潜在的问题
- 虽然当时对支付业务做了日志记录,但是在数据库里并未能区分业务来源和操作类型,导致我们对各项业务的流水、收入、支出难以统计和核算
数据一致性问题
支付系统仅有内外部渠道对账,而对内部的业务数据没有做好对账事宜,经常是在用户反馈异常问题后我们才能知晓
支付系统2.0
- 巨大的单体应用必须要拆分,在拆分之前,需要确定业务边界和系统边界,并对支付业务进行建模
- 构建完整的资金核算体系,以能够清晰地知晓各类业务的流水、收入、支出等
拆分系统边界
从3个维度对边界进行拆分
- 基于业务,拆分为面向支付业务和面向资金核算两套体系
- 面向支付业务,可拆分为收银台、交易核心、支付核心、渠道网关
- 面向资金核算,可拆分为会计系统、账务系统、清算系统、合规系统
- 其他基础服务的拆分,比如支付会员服务、支付风控和对账系统等
- 基于场景,例如依据支付流程等进行拆分
- 基于技术实现,例如出于对系统的性能等考虑进行拆分
将支付系统中的核心系统拆分为收银台、交易核心、支付核心、渠道网关、账务系统、会计系统、清算系统、合规系统等
交易核心
- 交易核心作为支付系统入口,对接上层的业务系统
- 支付系统有着数十张支付交易表,如何抽取合适的业务模型是最重要的事情
- 为了数据的统一性,对分散的数十张支付交易表进行了多表聚合,以及订单关联
- 支付的接入鉴权也放在了交易核心中实现
基础交易类型抽象
基于对业务的分析和理解,我们对交易核心的业务进行了抽象,抽象为10多种交易类型: - 比较熟悉的交易类型:担保交易、即时交易、充值、提现、担保退款、即时退款、转账等
- 不太常见的交易类型:提现退票、退款退单、异常退款、充值退款等
多表聚合及订单关联
对数十张支付交易表进行多表聚合是基于一张主表来实现的。而在这种情况下,业务订单如何保持唯一是我们需要考虑的事情。考虑到需要对上层业务保持极少的侵入性,因此在新设计的支付交易表中会有专门的字段用于做唯一键约束:业务识别码+业务订单号
订单追溯
支付管控
在交易核心里面做了支付接入的管控:授权和鉴权。为任何一个接入支付的业务分配唯一的业务标识码及授权的 Token。从而使得业务在支付接入时,需要带上 Token 和加盐过的加密数据
支付核心
将支付系统1.0中的支付模块切分为两层——交易核心和支付核心。交易核心面向上游业务,支付核心面向支付系统内部
对支付核心同样进行了支付类型的抽象:充值、提现、退款、转账,任何一个交易核心订单请求都能由这4种基础支付类型组合进而完成支付行为
支付核心需要基于系统、用户指令等完成各种各样的支付行为。按照简单的做法,我们可以在不同的分支上实现各种支付行为,但是这样可能会导致支付行为耦合,并使支付逻辑判断变得复杂。基于这种原因,我们对支付工具进行组件化拆分,封装为数十种支付工具,通过支付编排来执行支付行为
支付交易订单通过支付规则生成具体的支付请求(即支付核心记录),支付请求通过支付指令编排规则获取一组支付工具包,通过支付执行器完成对支付工具的调用执行
这样的封装使我们可以实现插件式开发,以及支付规则可配置化,继而让支付核心内部的支付工具互不影响并系统地简化
支付核心有一个比较重要的功能,即如何对支付异常进行处理——支付过程中的重复支付、部分支付、金额不一致、全额退款等异常都需要做异常退款处理
以部分支付为例,我们做了一个异常管理组件来处理这种异常,在“红包支付+优惠券支付+网关支付”组合支付中对每次的支付都进行上报,通过异常管理组件对部分支付成功的行为进行反向异常退款
渠道网关
渠道网关同样抽象了基础服务类型:支付、退款、提现、签约、查询等。同时,出于性能方面的考虑,将网关系统切分为两个子系统——网关核心和网关前置
- 网关核心负责渠道路由、渠道订单的管理及渠道分组
- 网关前置负责渠道适配、报文转换及外部通信
资金核算体系
- 会计系统:对业务运转信息进行管理、核查、披露,展现资金的来龙去脉
- 账务系统:由支付核心驱动,记录管理账户信息,直接反映用户的账户余额和资金变更明细
- 清算系统:由支付核心驱动,实现机构间资金关系应收应付的主被动清算及资金划拨
- 合规系统:基于支付数据,向资金监管方同步交易信息流和资金流,从而契合央行的合规监管要求
统一平台业务上下文
拆分服务后,如何保障业务信息在服务间流转而不丢失是我们需要考虑的问题。我们在平台中做了统一上下文的要素信息(唯一业务标识码),使其在整个支付平台链路中全程传递。通过统一平台业务上下文,我们能够在任何一个系统中清晰地看出是哪种业务,在哪种场景下,使用哪个渠道做了什么事情
- 商户:诸如蘑菇街电商交易、美丽说电商交易等
- 订单类型:基于交易核心的业务类型,诸如担保交易、即时交易、转账、提现等
- 订单场景:诸如电商预售、营销广告购买等
- 支付机构:诸如支付宝、微信等
数据一致性挑战
CAS
- 在整个支付平台中,对可能有并发冲突的系统做了CAS乐观锁,以交易核心、支付核心为例,通过状态的CAS乐观锁可以防止并发
- 同时也做了基于KVStore的分布式缓存锁来防止多数据之间的并发问题,例如解决重复支付问题等
接口幂等及异常补偿
- 要求整个支付系统中的所有服务、涉及数据变更的接口都保持接口幂等。全链路的幂等使重试成为可能
- 在诸如服务超时、网络异常的情况下,做了两种不同的异常补偿:基于消息中间件的准实时补偿及基于异常表的补偿
- 支付链路内部:以消息中间件准实时补偿为主,例如渠道网关和支付核心之间的交互补偿方式
- 支付链路对接外部业务系统:例如交易核心对电商交易支付成功的通知方式使用的是异常表补偿,在12小时内递衰10次通知
对账体系
在支付系统中,对账是数据一致性的最后一道防护
- 内外对账:以确保内部支付数据与第三方支付数据保持一致
- 内部业务对账:内部业务准实时对账平台,用于核对整个平台数据
内部业务准实时对账平台支持各种数据源的接入,目前基于系统解耦的考虑,我们更多地使用数据库事件变更中间件来接入对账双方的binlog数据,通过配置规则或者自定义的转换逻辑来进行双方的模型转换,从而通过对账核心进行数据核对
通过该系统,可以在5~25分钟之内发现异常数据
性能提升
主要对支付系统的性能进行以下几个方面的提升
- 读写分离
- 核心链路分库分表:全链路水平扩展
- 服务调用异步化
- 热点账户问题优化
- 事务切分
服务调用异步化
支付消息报
基于数据库事件中间件和消息队列来实现支付消息报。支付消息报基于交易核心数据聚合其支付数据,最终生成支付消息报。将原本需要在交易核心或者支付核心中调用下游业务方或者下游业务方实时查询的方式,转变为下游业务方通过接收消息推送的方式来获取数据,从而达到业务的解耦。同时,也简化了业务方数据获取的复杂度
外部支付异步化
通过独立网关渠道前置服务,将获取方式分为两种
- 针对支付链路,只是请求到渠道前置服务并拿到内部的支付凭证便结束
- 针对外部请求,由渠道前置服务异步向第三方支付发起请求
基于这种方式,与第三方支付的同步交互仅仅会阻塞渠道前置,而不会阻塞其他服务。对于密集型I/O和低CPU的系统,渠道前置的并发值可以设置得非常大
异步并行
支付系统服务化之后,核心链路上的服务多为 I/O 密集型服务
通过对业务进行分析,我们发现用户信息查询、额度查询、优惠查询这3个服务的调用无先后顺序
资金核算体系异步化
在支付平台中,资金核算体系各个子系统的会计系统数据来源于账务系统,账务系统、清算系统、合规系统数据来源于支付核心。其实基于对资金业务的分析,会计、清算、合规属于非强实时业务,因此可以通过数据变更中间件同步数据,对这3个系统进行解耦
清算系统、合规系统通过监听支付核心数据库中的数据变更来获取数据,会计系统通过监听账务系统的流水库数据变更来获取数据,从而对实时链路的非强实时业务进行解耦
热点账户问题优化
- 内部账户
- 在账务中不对内部账户进行记账,而是由会计通过另外一边的账务流水去补记分录
- 平台账户
- 在账务中做异步记账,并定时汇总记账即可
- 商家账户
- 通过分析其业务场景,我们发现担保入账、担保出账、佣金扣费等占用了绝大多数的商家账户操作
- 担保入账和出账:将商家担保账户切换到平台担保账户,基于流水去统计商家担保中的金额
- 扣费:做了一个排序的任务,进行单商家串行扣费及多商家并行扣费
账务记账事务拆分
- 出账和入账分离。出账成功则整体成功,而入账失败可以进行异步补账
- 在出账和入账中进行单边账、异步记账等处理,整个支付核心链路的事务就是更新账务余额及新增流水
稳定性提升
监控先行
提升稳定性之前,需要知道系统的运行情况,那么就必须要做线上系统监控,对关键指标进行管控
监控了核心链路的QPS、RT、并发量等,同时也基于支付核心,对依赖的服务QPS、RT进行监控。另外,也对依赖的数据库和缓存进行监控。通过在监控大盘中配置关键指标,能够比较清晰明了地看出目前核心链路的线上运行情况
分离核心链路
在核心链路分离的过程中,将链路中的各个服务拆分为核心服务和通用服务,或者是将一个服务切分为核心链路服务和通用查询服务两个服务
核心链路分离之后,能够确保核心链路在任何时候都不会受到其他通用业务的影响而出现稳定性问题
服务依赖梳理
- 梳理平台中的强弱依赖,判定哪些是强依赖,哪些是弱依赖
- 对弱依赖做好降级和超时保护,可以埋入降级开关、设置较短的超时时间
- 对强依赖的服务提出服务的SLA治理。比如账务记账功能,我们会要求系统不能崩溃、RT不能超过20ms、需要支撑8000QPS等,基于这些约定来做子服务的优化
限流降级
- 基于RPC服务框架Tesla的粗粒度限流,可控制服务级别和方法级别
- 基于蘑菇街自研的细粒度限流降级系统(Spirit),可以在单个方法中做更细粒度的限流降级
基于Spirit,能够在担保交易下单时,通过识别平台资源标识对蘑菇街和美丽说的流量进行隔离和管控
单单依靠QPS或者并发限流都不能完全做好限流降级保护,需要两者相结合才能达到所需的效果
通过对服务依赖的梳理,我们在各种弱依赖的服务中埋入了一些降级开关。通过自研的降级推送平台,一旦依赖服务出现问题或者不可用,就可以快速对该服务进行降级操作
压测
- 线上压测系统,通过分析业务场景,构建与线上真实场景几乎一致的测试模型。压测模型越与真实场景一致,压测的效果越好,对系统的把控越准确
- 通过构建线上数据影子库,压测产生的测试数据会全量写入影子库。通过影子库,复用与线上正式业务一致的环境、部署、机器资源,这样我们能够在压测对正常业务无侵入的情况下对系统做准确的把脉
- 线上业务也分为两部分。一部分是单机性能压测,主要是分析单机的性能水位和各项指标;另外一部分是链路压测,主要是验证系统的稳定性和服务短板
成效
业务支撑能力
- 快速支撑业务。之前在接入新业务时,很大概率上需要新增交易表之后再开发上线。在升级之后,基本上只需要进行接入配置即可
- 基于业务接入授权管控及统一平台上下文,能够对业务进行细分,从而对各项业务的资金情况进行细分和准确的核实
- 合规系统符合央行的资金监管要求,为用户、商户提供了强有力的资金安全保障
系统服务能力
- 平台容量方面:在2016年双11大促的压测中,我们在链路数据库都扩围两组物理机的情况下,使支付量稳定在3000QPS。由于目前没有需求,未对数据库物理机扩围到极限,因此系统的极限性能不能完全确定,但是按照预估,其可以支持 10000QPS以上的业务量
- 机器利用率方面:在容量相同的情况下,我们的应用数量减少为原有的1/3
- 链路的性能方面:如图14.28所示,以担保交易为例,交易核心的担保收单 RT 几乎稳定在10ms,而收银台订单查询RT为50ms,支付请求RT为50ms,支付回调RT为80ms左右
15 金融撮合架构(李伟山)
– 写的是啥
16 一线架构师带你玩性能优化(孔庆龙)
16.1 什么是系统优化
一方面是系统化地对IT系统或交易链上的每个环节进行分析并优化,另一方面是对单一系统进行瓶颈点分析和优化。这两方面的优化目标大致相同,无非是提高系统的响应速度、吞吐量、降低各层耦合,以灵活应对市场需要
系统优化主要在如下三个层面上进行
- IT系统治理层:这一层面的优化不只是性能优化,还包括为适应业务架构变化而带来的应用架构优化(如应用分层、服务治理等)
- 系统层:这一层面的优化包括业务流程优化、数据流程优化(如提高系统负载、减少系统开销等)
- 基础设施层:这一层面的优化主要是提高IaaS平台的能力(如使弹性集群具备横向扩展能力、支持资源快速上下线和转移等)
16.2 系统优化的方法论、思路和原则
16.2.1 常用方法论
- 阿姆达尔定律(Amdahl Law):根据公式S=1/(1−a+a/n)分析每次对整体效果影响最大的点,并进行优化
- 不访问不必要的数据:减少交易线上的不必要环节,减少故障点和维护点
- 就近加载,缓存为王
- 对交易链进行优化,提高吞吐量:减少串行同步调用,合理拆分(垂直/水平拆分),规则前置
- 故障隔离:不要因为一个系统瓶颈压垮整个交易平台
- 具备良好的扩展能力:合理地利用资源,提高处理效率并避免单点故障
- 性能和功能同等重要:若交易链上有5个性能变为设计阶段时的90%,则整体性能会变为设计时的59%
16.2.2 优化思路
- 了解现状,发现问题
- 确定清晰的优化目标,分析现状与目标的差距并确定执行路线
- 对系统进行拆分,分别对逻辑层(Web层、业务层、持久化层)和物理层(客户端、网络、应用服务器、数据库服务器)进行优化
- 利用工具对系统进行监控和测试,并对监控和测试结果进行分析
- 科学地对系统进行优化
- 遵循一定的程序:监控/性能测试→分析瓶颈→罗列瓶颈的因素→验证瓶颈因素→修改系统→确认是否达到优化目标
- 确定影响性能的因素:CPU、内存、I/O、网络或其他因素
- 找出主要的瓶颈,优先解决关键因素,再重复监控或测试验证
- 避免过度优化,一次修改一个瓶颈,不要对不需要的地方进行优化
- 提高CPU性能:写出更快的代码,设计出更好的算法,减少短期生存的对象
- 提高内存性能:减少长期生存的对象
- 提高I/O性能:重新设计应用,减少I/O的交互
- 缓存为王:适度缓存,做到最大化发挥数据库缓存、应用端缓存、客户端缓存的作用
16.2.3 优化原则
- 在应用系统的设计、开发过程中,应当始终把性能放在考虑的范围内
- 确定清晰明确的性能目标是关键
- 性能优化是伴随整个项目周期的,最好分阶段设定目标,在达到预期性能目标之后即可对本阶段工作进行总结和知识转移,进入下一阶段的优化工作
- 必须保证优化后的程序可以正确运行
- 性能更大程度上取决于良好的设计,优化技巧只是一个辅助手段
- 优化过程是迭代渐进的过程,每次优化的结果都要反馈到后续的代码开发中
- 性能优化不能以牺牲代码的可读性和维护性为代价
16.3 性能优化
16.3.1 常见的性能问题
常见的客户端性能问题
- 加载慢:第一次启动慢或者重新加载慢
- 无响应:事件突发导致页面假死
- 受网络带宽影响严重:因为需要下载大量资源文件,所以在一些网络环境不好的地区页面加载缓慢
- JS(JavaScript)内存溢出:频繁地对对象属性进行操作,造成内存被大量占用,最终溢出
常见的J2EE系统性能问题
- 内存泄漏:在运行过程中,内存不断被占用而不能被回收,内存使用率随着时间的推移或负载的增加呈线性增长,系统处理效率随着时间的推移或并发的增加而下降,直至将分配给JVM的内存用尽
- 资源泄漏:将资源打开后未关闭或未成功关闭而导致的问题。这些资源包括数据源连接、文件流等。当这些资源经常被打开而未能成功关闭时,就会导致资源泄漏。数据源连接泄漏是常见的资源泄漏问题
- 过载:过度使用系统,超出其所能承受的负荷
- 内部资源瓶颈:资源被过度使用或分配不足而引起资源瓶颈问题
- 线程阻塞、线程死锁:线程执行某段代码时,无法获得相关的同步锁而造成通信阻塞
- 应用系统响应慢:由于应用算法未优化,不合理地读取大量数据,SQL缺少索引或存在过多表关联而导致响应时间过长,执行变慢
- 应用系统不稳定:应用系统的响应出现时快时慢的现象
- 应用系统中有各种各样的异常情况发生:有些是中间件服务器抛出的异常,有些是数据端抛出的异常
常见的数据库问题
- 死锁:由于联机服务过早开启数据库事务,第三方服务未及时响应,使得锁和事务无法提交而导致数据库死锁
- I/O繁忙:由于存在不良SQL或业务逻辑设计不合理而导致大量I/O等待
- CPU 使用率居高不下:由于高并发或缓存穿透而导致数据库 CPU 居高不下或忽高忽低
16.3.2 性能优化的具体工作
交易线优化
- 最短路径:减少不必要的环节,避免故障点
- 交易完整性:通过冲正或补偿交易等确保交易线各环节的事物一致性
- 故障隔离和快速定位:屏蔽异常情况对正常交易的影响,通过交易码或错误码快速定位问题
- 流量控制原则:可以对服务通道进行流量控制,并结合优先级设置优先处理级别高的业务
- 超时控制漏斗原则:尽量使交易线上前端系统的超时设置大于后端系统
- 熔断和故障隔离原则:避免由于某个服务提供者出现故障而导致整个交易线不可用
- 监控报警:对服务调用状态进行监控并设置预警值,在发生异常时可以及时通知相关人员进行干预处理,缩短异常影响范围
在软件版本迭代时,很少有人能把系统的全部细节都考虑清楚,所以要靠规范来确定治理范围,而不是靠人
客户端优化
- 分析瓶颈点,有针对性地进行优化
- 通过gzip、deflate压缩来减少客户端网络的下载流量
- 使用压缩工具对JS进行压缩
- 删除、合并脚本、样式表及图片,减少GET请求
- 无阻塞加载JS
- 预加载图片、CSS样式、JS脚本
- 按需加载JS脚本
- 优化JS处理方法,提升页面处理速度
服务器端优化
16.3.3 JVM优化
《深入理解Java虚拟机:JVM高级特性与最佳实践》
16.3.4 SQL优化
17 性能优化的常见模式及趋势(陈显铭)
性能优化整体上可以分为两类:单应用优化和结构型优化
- 单应用优化:关注单系统瓶颈,通过解决单系统瓶颈提升性能
- 结构型优化:通过改造链路结构和配比进行整体性能的优化
17.3 单应用优化
确定性能瓶颈/热点的常见方法
- 性能压测:通过工具、人工等方式量化运行时的性能情况
- 业务/代码梳理:通过代码走读发现资源消耗热点,通过统计代码对资源的操作量化代码对资源的消耗(比如一个业务操作会进行多少次数据库调用,进行多少次服务运算等方式)
压测时通常观察的内容及其所使用的工具
- 内存的使用情况:MAT、GC日志、vmstat
- CPU情况:Linux下的top命令
- I/O情况:iostat
- 网络情况:Netstat
- 热点代码:JProfiler、BTrace、JStack、JStat
常见的优化手段及模式
- 静态化:动态数据和静态数据分离
- 异步化:使用异步化减少主流程中的非关键业务逻辑
- 并行化:使用多线程并发处理,缩短响应时间
- 内存优化:减小对象所占用的空间,减少对象创建的数量,优化数据模型
- 去重复运算:优化业务逻辑,或者使用缓存
- 减少数据库操作:为此,需要减少数据冗余、数据缓存等
- 缩短数据库事务:可以考虑使用短事务、异步化、最终一致性等方式
- 精简代码逻辑:去除冗余代码,诸如重复判断的代码
- 精简日志操作:要关注日志大小,注意I/O上的瓶颈。日志太多,说明生成的String也很多,会增加GC的负担
17.4 结构型优化
– 常见的网站架构升级演进过程
18 性能优化之几种常见的压测模型及其优缺点(陈显铭)
–没什么干货
19 缓存为王——无线缓存架构优化(高磊)
–移动端的没什么兴趣