写点什么

蚂蚁金服 - 财富编码军规

作者:Beaver
  • 2022 年 3 月 05 日
  • 本文字数:7026 字

    阅读完需:约 23 分钟

“    蚂蚁金服-财富编码军规

无规矩不成方圆  


01



基础编码


并发控制,默认使用悲观锁,一锁二判三更新,乐观引入须谨慎。


为防止数据并行写入造成状态回退或乱序,原则上使用悲观锁,先对需要操作的数据进行查询检索并加锁,判断当前状态符合修改条件后再操作数据,最后提交事务释放锁。乐观锁,虽然性能上更好,但设计上和维护上都更复杂容易出错,如须使用,务必进行充分的方案评估,后续改动也要特别注意防范因乐观锁条件被破坏而造成的业务错误。


幂等拦截,幂等新老要兼容,字段约束需一致,异常场景防击穿。


上下游对幂等的理解(包括请求中用于幂等控制的字段,幂等后返回的结果,幂等后的业务处置等),需要确保单一、明确,避免出现二义性理解。且幂等设计不仅包括公司内部各系统,与外部交互也需要确认幂等字段的有效性,例如文件中的外部单据号等。同时,幂等设计也要考虑异常场景,下游在无法明确业务处理结果状态时,不应返回上游明确成功、失败或幂等的结果,避免上游错误处理。


状态推进,流转设计要完整,状态推进凭指令,业务终态不可逆。


状态机设计要考虑完整,避免业务状态流转设计缺失导致业务无法正常处理。状态推进一定要基于明确的业务指令或者集成契约,没有明确的业务指令系统不能擅自推进状态机,比如不能单纯因为技术的超时就把状态机推进为失败,实际上超时可能是成功也可能是失败。状态机的终态设计,一定要做好 review,终态意味着不再更改,无论何时查询这笔业务都是同一结果,其他系统可以根据这个状态做进一步的决策动作。


对象设置,成员变量慎赋值,引值引址需明晰,对象比较用 equals。


对于成员变量的使用需要判断程序处理中对象是否是单例模式,单例模式下存在多线程访问会对成员变量造成并发修改情况,导致脏读脏写。日常设计中例如缓存对象值获取、money 对象处理一定要分清楚引值/引址,是想在原有对象上进行修改,还是克隆一个新对象进行处理需要区分开,引值需要深拷贝,引址并发场景防脏写,避免使用语意不清晰导致原始对象被篡改造成数据异常甚至资金风险。对象比较必须使用 equals 方法,不接受任何理由的空指针。


数据库表,SQL 必须带字段,where 条件有索引,索引不含隐式转。


SQL 查询必须指明要查询的字段,杜绝 select *。查询条件上要有索引,避免全表扫描影响数据库性能。且查询条件必须同 DB 字段类型一致,避免查询过程 DB 进行类型隐式转换造成索引不可用。补充:由于 OB 频繁写删表容易出现数据积压或者并发时容易导致执行计划走错执行全表扫描,因此设计中需要指定 HINT,且因为 ZDAL 分库分表替换逻辑不针对 HINT 中表名替换,所以 HINT 中表应该设置为别名方式保证正确指向对象分表。


时间设置,关注时区和时令,避免设置当地值,string 传值带时区。


时间设置要关注闰年、夏令时、时区。服务器时间都要设置成为 UTC(海外)或者 GMT+8(国内),一定不能设为当地时间(北美、欧洲、澳洲一些国家都有夏令时)。时间不要用 timestamp,要用 datetime。用 string 传时间,一定要 ISO 格式带上时区信息。


异常防御,请求校验防篡改,异常 catch 不能吞,线程对象清理好。


对于用户或机构通过各种端提交的数据,必须校验其合法性、完整性、正确性和真实性,避免各种非法篡改导致的安全或水平权限问题。代码编写中,对于 catch 住的异常,必须明确给出处理方式(至少要保证异常被日志记录),禁止不做任何处理就截断,严禁吞掉异常。为避免线程复用对上下文数据造成污染,上下文变量的设置与清除必须配对,在相应的 finally 中清理,避免内存泄漏。


代码质量,CR 单测集成测,结果断言边界值,全量回归不能少。


代码上线前必须做好 CodeReview,且必须由编码外的另一个同学完成 CR 检查后才可推进到下一步流程(包含代码/配置变更等多种场景)。单测用例要做好结果断言和边界值测试,代码变更后,一定要通过全量测试回归后才可以发布,不能只测试修改部分。


02

架构设计


防御编程,强弱依赖要合理,单点异常可切换,线程隔离和限流。


核心系统禁止强依赖非核心系统,核心链路必须能主动降级非核心链路(关注弱依赖节点超时时间设置问题,避免弱依赖变“强依赖”)。如业务场景或部署架构无法避免单点,那么必须设计去中心化或者做好备份架构,具备切换功能。做好线程隔离设计,避免不重要的服务异常影响到重要的服务。同时,容量保护是应用提供服务的必备防御条件之一,需要常态化配置限流。


网络调用,交互三态要牢记,错误定义要单一,未决处理遵协议。


交互三态,成功、失败、未知在一个接口设计中必须包含,成功和失败必须明确返回结果码,返回码不可有二义性,在未知返回处理上,必须遵照协议约定,决定是否重新发起业务操作或等待回查结果。


接口规约,字段约定要明确,业务含义要清晰,接口升级要兼容。


接口交互约定上,业务相关字段必须明确、单一,对于业务透传数据,也必须约定透传的 KEY 枚举和内容大小,确保交互双方业务理解一致。接口升级,必须兼容原有接口请求和返回,不应在业务明确字段上叠加业务含义或破坏原有字段业务含义,令字段形成二义。对于业务特殊,必须破坏或废弃原有接口的情况,建议重开接口并设计相关切换及核对逻辑。


LDC 容灾,分 zone 逻辑要清晰,FO 能力需具备,灾备容量要对等。


LDC 架构下进行容灾设计时,首先要清晰理解 Gzone、Rzone、Czone 的逻辑及特点,并了解自身业务流量的分布情况。要充分考虑 FailOver,具备快速切换能力。同时,灾备机房的容量要对等,通过常态化演练来保鲜能力。补充:异地容灾时,状态型数据走三地五中心自动恢复,流水型数据走 RFO 库(Remote FailOver 库)恢复。三地五中心部署后带来事务跨城提交耗时上涨,业务上应尽量减少频繁小事务提交,合并成大事务提交来减少事务提交耗时对业务整体耗时的影响。


03

资金安全


资金风险,证账实要对清楚,业务规则细分析,配置上下需一致。


资金风险重点关注一致性,业务型,配置型风险,一致性通过证账实理出关系,业务型关注业务规则类(准入,金额计算等)的风险场景,配置型的关注上下游配置一致性,相关风险点必须部署核对。


金额计算,注意币种和元分,计算使用 Money 类,外汇买卖方向对。


金额计算主要涉及到上下游币种一致、计算精度、外汇转换这 3 个重点。上下游必须保持币种一致,是元还是分要明确,防止错误使用导致金额放大缩小,所有的地方,包括数据库存储,都要用三元组来表示金额:币种,amount,单位(元还是分);计算使用 money 类,避免精度问题,比如到小数点后几位的四舍五入;外汇双方保持方向一致,都是一个币种到另一个币种的转换。


核对设计,过程终态均核对,包含金额状态码,中间账户对余额。


核对设计的时候,一般考虑对过程和终态都做核对,核对要素包括金额、状态、和账户一致,涉及到中间过渡户的账号,必须部署流入流出自平衡+流入流出汇总核对,或者余额核对,保障账户资金正确。


资金应急,上报止血要及时,数据捞取要复核,应急调账需审批。


资金应急操作,发现资损问题要第一时间上报信息安排处理,止血方案要经过充分业务决策。评估影响面必须由业务+SRE 双方复核。应急订正必须有一方审批确认,调账涉及账户资金操作,需要谨慎,涉及用户账户调账必须有客满外呼确认。


04

中间件使用


消息使用,groupId 要唯一,重复投递须关注,事务回查防悬挂。


不论是消息发布者或消费者,groupId 只能被定义一次,要保证全局唯一;消息投递不保证不重复,因此订阅端需要依据业务属性做好幂等处理;事务消息如果没有实现事务回查,会造成消息悬挂。


缓存设计,缓存击穿要兜底,过期设计去热点,存储容量需考虑。


不管使用何种缓存,如业务属于不可降级核心链路,须确保缓存被击穿时,后端数据库容量可以承担对应的线上流量。在缓存失效设计上,需考虑打散,避免同一时间大量请求落到 DB 形成热点,缓存 KEY 规则也应避免形成热点 KEY。缓存存储容量消耗要提前计算清楚。


事务处理,悬挂告警要及时,严禁造成空回滚,确保最终一致性。


xts 二阶段可能会出现悬挂的情况,出现悬挂可能是系统 bug、数据异常、超时、空回滚等原因。因此需配置相应的事务悬挂监控,确保事务悬挂发生后同学能第一时间介入处理。对于分布式事务,只能做到最终一致性,部分同学会把它与本地事务强一致性混淆,这需要重点注意。比如 A 系统调用 B 系统更新数据,一阶段已经成功,在 B 系统内部二阶段还没处理完的时候,C 系统马上去读取 B 系统的数据,可能无法读取到 A 系统的调用结果。


调度任务,调度重叠要避免,捞取数据可配置,熔断能力需具备。


三层分发任务调度,需要控制调度频率,避免出现上个任务尚未结束而下个任务就已开始的并发场景。分布式调度场景捞取数据必须可配置,以灵活处理数据。如果数据不可配置或者并发数控制不好,非常容易将下游系统打挂。当执行层数据量较大时,要有对应的熔断措施(可以通过上一步的配置来减轻压力),且执行调度任务的线程池要独立配置,避免与业务混布导致调度任务无法及时处理。


限流配置,增量覆盖要分清,删除规则要小心,异常限流调算法。


guardian 限流,覆盖推送仅生效本次推送的规则,增量推送会生效本次和之前推送的规则。删除规则注意避免产生野规则(管控上规则已删除,规则还实际存在),先关闭规则,再推送这条规则,最后删除这条规则。限流排查先看流量记录日志,确认是否有流量,确认是否能匹配上规则。误限严重时考虑用令牌桶算法,严格不允许超放的用 QPS 计数算法。


ZDAL 使用,连接数量需评估,耗时上涨要警惕,FO 机制来保障。


数据库的连接池总数是一种有限资源,线上需要根据业务的耗时及机器实例数来评估一个合理的数值。日常 SQL 耗时上涨需要实时关注,数据库出现问题了第一时间会反馈到耗时上面。数据层的 FO 机制是保障数据库最后一道防线被击溃时的兜底方式,是非常有效的应急机制。


RPC 调用,接口 ZoneRoute 要注意,AntVip 需配置,超时设置要谨慎。


LDC 的场景下建议配置 ZoneRoute,如果 AntVIP 没有配置,跨城的调用将会出现问题。配置超时时间时要考虑上下游依赖和调用链路的整体情况,避免采用默认的较大超时时间设置,当出现下游异常的时候导致上游严重堵塞。


DRM 使用,GetSet 注解齐,生产推送上九州,推前内容勤比对。


接入 DRM,设计 class 和 field,并在 class 加上注解 DResource,field 加上注解 DAttribute,这影响到 dataId 的注册。另外,field 的 setter 方法的执行逻辑不要超过 5s,超过 DRM 可能认为设置失败。而 getter 方法的实现则影响到在 opssla 界面上展示机器的值。根据变更管控的要求,配置推送不应在 opssla 上,合规做法是上九州推送。在推送配置导致的生产故障中配置内容有问题占了绝大一部分,因此请各位同学慎之又慎。


05


数据质量


数据研发,研发规范须遵守,冒烟测试不可少,仿真灰度保稳定。


数据研发规范对日常研发中需求、设计、开发、测试、发布的流程及规范都有明确的要求,需要大家遵守。同时在任务上线前,需要利用线上全量的数据进行冒烟、仿真、灰度测试,确保任务执行成功且 DQC 强规则、业务核对监控通过,保障任务上线稳定。


引擎变更,变更方案要评审,灰度测试融演练,巡检免疫要到位。


当工具平台、引擎发起新版本的变更时,先要发起变更方案的评审,在评审通过后,要进行灰度,并且在灰度的过程中要进行充分的测试。日常需要在灰度环境进行攻防演练,模拟故障案例,检验引擎生产稳定可靠。引擎端每次变更后都需要针对整体链路进行风险巡检,降低变更引起的风险。


监控核对,任务监控要添加,内容核对要重视,及时降噪禁麻木。


任务在上线前必须配置表级基础监控指标,包括主键非空、无重复数据,全量表非空。针对重要的业务字段,需要根据业务含义配置监控核对,确保数据内容稳定可靠。在日常保障的过程中,需要保持监控的新鲜度,如出现无用的监控需要及时下线,避免对应急判断做出错误的干扰。


风险治理,潜在风险配巡检,风险接收须治理,不治升级要限权。


对于"没有配置 DQC 强规则"、"任务告警电话没有打开"、"SQL 代码中使用临时表"等潜在风险点,可以通过配置数据链路的巡检规则进行主动发现,相关同学接收到系统推送的治理通知后,表明存在风险点需及时治理优化。为了防范未来风险点触发故障,如果 owner 长时间不进行治理,告警会升级到主管并限制 D2/DG 的发布权限。


业务保障,资损舆情录场景,时效保障用基线,上下协同保业务。


业务质量保障,如果支撑的业务有较高舆情或者资损风险,末端任务需要录入到场景中进行质量保障,并根据风险高低定义风险评级。如果这块业务对数据的产出时效有非常高的要求,可以申请基线进行时效高保。最终一旦注册了场景和基线,蚂蚁整个数据风险体系就会协同全链路的同学共同为最终业务进行保障。基线简介


06

生产变更


提前计划,下周变更本周理,重大高危需报备,沟通确认应有效。


每周提前收集汇总下周的变更,留足充分的时间提前确定监控 &应急手段,进行变更风险防控,如:在变更核心部署防御规则,仿真模拟等。若涉及重大高危变更,需按照各域要求进行报备,部分业务域需审批通过后方可执行。实习期和试用期的同学需要在师兄的帮助下进行线上变更。沟通触达必须有效,仅钉钉不能作为正式确认的手段,各种正式确认(例如,能否开量),必须邮件确认(或者是 Aone 里面的缺陷或者需求等),要有明确的“yes” 或“no”。


灰度分批,生产之前先灰度,分批操作控比例,关键业务须盯盘。


在生产环境全量生效变更风险极高,变更误操作、变更触发代码缺陷等未知问题都可能造成线上故障。通过控制变更生效范围可以降低变更风险影响面,也使得问题在扩散至全集群造成重大影响之前,在小范围内暴露、发现和终止。因此,变更需要先经过灰度仿真环境,然后才能在生产操作,生产环境也需要分批次逐步进行。


防御检测,变更前后配校验,监控巡检覆盖全,防御规则勤演练。


变更系统接入变更核心,通过配置前置准入校验规则和后置风险发现的规则,系统化地阻塞风险和发现风险。规则对监控巡检指标的充分覆盖才能保证变更风险不遗漏。且规则需要定期演练保证有效性。


变更观察,恢复手段提前定,应急操作有人盯,出现问题变更停。


变更过程需要有人持续关注线上业务稳定性。变更期间出现的问题,无论是系统化的检测规则识别到的还是人工观测识别,第一时间暂停变更,排查无误才能继续。


变更执行,严格遵循三板斧,监控灰度可应急,违背规则要处罚。


无论是利用系统化的三板斧能力还是执行过程的人工控制,变更执行人需要确保变更过程先灰度再分批,确保每个批次进行了充分的监控观察,确保无误才能进入下一个环境或者批次。未遵循变更三板斧原则(可监控、可灰度、可应急),或代码和配置变更未经过 code review 直接上线而触发的线上故障,将依照《蚂蚁金服生产故障处罚条例》进行处罚。


07

应急止血


应急值班,手机电脑随身带,电量网络要确保,暂时离开有备份。


应急值班轮值时,确保手机和电脑随身携带,电量充足,网络通畅,随时做好应急准备;暂时离开或者休假需要有备份 owner 并交接明确。


应急响应,接到告警快响应,出现风险速升级,预案执行要谨慎。


接到告警第一时间(5 分钟内)上线处理。如故障影响存在扩大/舆情风险需要迅速升级至管理层,由管理层共同决策处理。应急预案执行前需检查确认有效性,防止发生次生故障。


应急过程,恢复止血是第一,高危操作先灰度,谨慎小心防扩大。


应急过程中,以恢复止血为首要任务,不要先着急调查根因,更不要先追究责任。处理过程中,可随时联系周边同学协助处理(包括业务监控和信息通报等)。遇到高危的应急操作需要先通过灰度或 bata 方式试探检查,防止由于操作不当导致二次故障或者故障影响扩大。


应急手段,发现变更先回滚,容量不够降和限,容灾切换来兜底。


应急止血时,优先确认是否有相关变更,如发现变更优先回滚。如发现容量不够则及时采取降级和限流。如短期内没有有效止血手段,终极大招需通过机房级容灾切换来恢复业务。


应急建设,实战攻防日常练,定位自愈助提升,历史故障取经验。


应急建设在于平时积累,通过常态化攻防演练来锻炼人的应急能力,通过定位和自愈平台来提升自动化应急响应速度。并且需要吸取历史故障的教训,将经验沉淀到平台或者沉淀成规范,避免问题重复发生。


08

客户端 &前端


分工边界,复杂逻辑给后端,前端优先做呈现,系分对齐不遗漏。


开发分工需做好分层,服务端发版更灵活,所以复杂业务逻辑交由后端处理,前端优先或仅做展现。开发过程中涉及的边界、接口、平台(IOS 和 Android)差异需要在前期的系分阶段对齐。


稳定可靠,系统机型要兼容,异常边界需关注,判空保护不能少。


稳定健壮性方面,需要关注不同厂商、不同系统版本以及不同机型的接口/UI 兼容性。开放式接口的参数处理需额外要关注异常值、边界值,对象处理的判空防护也不能少。重点关注闪退和白屏问题,提前做好专项测试和降级预案。


性能体验,降低渲染复杂度,减少施压主线程,异步请求不阻塞。


性能体验方面,需注意精简视图层级、避免过渡绘制,降低测量、布局、绘制各阶段成本。应尽量规避主线程文件、数据等读写耗时操作,合理使用异步任务,提升界面流畅度。小程序启动耗时不超过 2.5s,且不能因变更劣化超 10%。


数据保护,个人信息先脱敏,资产信息可隐藏,日志隔离不外泄。


在数据安全方面,收集的用户个人信息需要除去敏感信息,如常见的身份证号,银行卡号,存款金额等数据在设计开发或日志打印是都需要隐藏,对于不同业务、不同安全级别的日志需要分类隔离存储或加密存储以减少外泄风险。


转载:蚂蚁金服-财富编码军规



转自:https://blog.csdn.net/doctor_who2004/article/details/123297487?spm=1001.2014.3001.5501


用户头像

Beaver

关注

还未添加个人签名 2018.02.12 加入

还未添加个人简介

评论

发布
暂无评论
蚂蚁金服-财富编码军规_编码规范_Beaver_InfoQ写作平台