写点什么

美团点评收银台前端可用性保障实践

  • 2017-07-30
  • 本文字数:5138 字

    阅读完需:约 17 分钟

本文主要讨论的是前端可用性相关话题,以在美团点评移动端网页收银台的实践为例,讲解收银台前端是如何保障可用性的。

收银台是什么?为什么要保障收银台可用性?

(点击放大图像)

在美团点评,收银台是一个横向的业务基础服务,所有业务的闭环环节。所有线上业务最终完成交易全部由收银台来完成,它的重要性不言而喻,对于收银台来说,有三点需要保障,这三点分别是『可用性』、『体验』、『安全』,他们都共同为一个重要指标服务,那就是『支付成功率』,而对支付成功率影响最大的就是可用性。
可用性对支付成功率的影响有多大?一个小小的 Bug 上线后即使及时发现并回滚,可能也会造成几百上千万的营业额损失,这对于整个团队来说是无法接受的。所以,对于收银台来说,保障可用性是第一优先级。

如何定义前端服务可用性?

一般可用性都是说后端服务的可用性,都说我们的服务可用性到了几个 9,很少有人把可用性放到前端来。其实对于任何一个有 UI 交互流程的业务,都会有前端服务可用性,后端的可用性做的再高,前端一个按钮写的有问题点击不起作用也会导致用户无法完成流程。

前端服务可用性包含三个部分:

  • 前端代码可用性(测试质量,线上异常)
  • 静态资源服务可用性
  • 网络链路可用性(DNS 劫持,网络性能)

既从业务后台服务往上,一直到用户界面,一切都是前端服务,这里面一切用户可能遇到的问题都是前端可用性的范畴。

这就是我们认为的前端可用性,收银台的可用性建设就是围绕着这三个部分展开的。

如何衡量前端服务可用性?

前端服务的可用性衡量和后端的衡量方法相类似,既不考虑影响范围大小,只考虑存在故障的时常,最大化考量可用性。可用性指标不是为了让我们通过复杂的算法来减小事故对可用性计算的影响,而是为了激励我们在可观测范围内做到没有问题,越做越好。影响用户数,影响订单数,影响 GMV 等指标更多的是用于做事故定级。

哪里容易出问题?

前端代码可用性:

  • 空指针问题是困扰前端的一个大问题,由于 JS 本身是弱类型动态语言,无法在开发及编译过程中通过工具推导出可能出现问题的点,进而在前端研发过程中很容易疏忽造成空指针问题;
  • 业务逻辑覆盖率指的是在业务项目当中,代码对动态逻辑的处理能力,往往在一些复杂的业务项目当中,逻辑混乱交错,前端的展示和进一步的动作由后端控制,这种情况下复杂的逻辑交织在一起产生无数分支,逻辑环境难以模拟,进而很容易在逻辑的处理上产生疏忽;
  • 兼容性问题困扰着各个端的研发,对于前端来说,要面临的环境更多,包括平台、系统版本、浏览器版本、WebView 版本、Hybrid 桥版本等等,很难从测试角度全部覆盖;

静态资源服务可用性:

  • 前端静态资源服务链的稳定性,例如 NGINX 、Node 等等;
  • CDN 并不是任何时候都可以正常提供服务的,可能会遇到 SSL 证书链问题,回源服务可用性问题等等;

网络链路稳定性:

  • DNS 劫持是一个老大难问题,大部分情况下是运营商为了节省跨省流量结算的费用而进行 DNS 劫持,走内部的缓存,还有一部分情况是广告,想象一下把收银台的代码劫持并插入一个运营商广告是有多可怕;

大块的问题就是上述几种,细枝末节的问题就不在这里一一细表,那么具体我们是怎么解决的呢?

怎样保障才能被信服?

记得刚刚开始负责支付业务的时候,老板 (rank) 经常问一个问题:“收银台稳定性怎么保障?”,我当时想的就比较简单,无非就是流程保障、测试保障等等,但这不是老板想听的,不然他也不会老问我,显然是当时没有回答出他想要的答案。现在想想真是 “too young too simple, some times naive”。

支付这样一个特殊的业务有它对可用性独到的要求,对于可用性保障上必然不是任何业务都会用到的那老几样儿。老板想听的是对稳定性保障的独到见解,可复制的方法,有可用性保障的理论基础,让任何一个日后负责这个业务的人都能够照方抓药,保障前端服务的稳定性。

现在总结起来可用性的保障分为三个阶段:

  • 事前
  • 事中
  • 事后

保障手段分为三个大类:

  • 软的
  • 硬的
  • 根源的

「软的」是指用“人”来保障的部分:

  • 流程保障
  • 规范保障
  • 测试保障

「硬的」是指用“工程工具”来保障的部分:

  • 静态代码检查
  • 单测
  • Web 自动化测试
  • 持续集成
  • 线上前端异常监控
  • 业务异常监控
  • 前端服务异常监控
  • 网络异常监控

「根源的」是整个可用性保障的核心,是指通过“技术选型” 来让系统更健壮。这里面有两个核心点:

一、技术选型要简单稳健

要求在具备伸缩性的基础下避免任何复杂的不可控技术方案。核心链路上的所有代码团队要具备维护能力,要减少外部依赖;

这里面有一个关键的选型概念就是 「场景契合度」,技术选型不是你愿意用什么,你熟悉用什么,是在这个业务场景和团队规模下需要你用什么。

举个例子,收银台是一个单页应用,之所以设计成单页应用是因为它涉及到的视图跳转和数据传递太多,单页应用相比多页更具优势。那么在选型的时候我们当时有 React, Angular, Ember 等一线前端 SPA 框架可以选,但最后我们还是自己做了一个简单的视图生命周期管理工具,为什么?

  • 「场景契合度」,React Angular 等前端框架更适合极端复杂的大型单页应用,为了能够更好的处理这种复杂度采用了一系列厚重的工具去约束研发的过程,其中还包含一些这个项目不会遇到的问题的优化,例如渲染优化等等。对于收银台来讲,单个视图中的复杂度并没有那么高,可以遇到前端渲染性能瓶颈的项目并不多;
  • 「源码维护能力」,收银台作为核心链路中的核心业务,在技术上绝对不允许被动,团队必须具有核心代码的维护能力,而依照我们当时的团队规模,这是不现实的;

在收银台这个 SPA 场景里,我们只需要视图生命周期管理这个功能。所以,我们参考 Cocoa ViewController 的生命周期设计实现了一个简单的单页视图工具「Cyra」,它只负责视图生命周期的管理,简单、拓展性高、源码可维护无外部依赖。

(点击放大图像)

(点击放大图像)

二、避免出现核心链路上的可用性短板

举个例子,网页首帧渲染优化有三种常见方式:

  • 手工预渲染
  • 编译预渲染
  • 服务器预渲染(SSR)

其优化的核心内容就是把尽可能多的首帧渲染所需信息在第一个请求的响应中给出,也就是主文档请求。让用户能够尽可能快的看到内容。

从优化效果上来讲,SSR 的效果最好,它可以把 JS、CSS、HTML 以外的动态的数据一起通过第一个响应返回回来。

但是,最后我们选择的是编译预渲染,为什么?

先说什么是 SSR,SSR 这个概念是新提出来的,但原理上很早就存在,早年间一直都是 SSR,有服务器端把页面拼装好传递给客户端,类似 JSP、ASP 这种技术,和佛家的人生三境界一样,禅中彻悟后又回去了,就像现在的前端服务化很难做到当年微软 ASP.NET Web Form 那个水平。

后来前端行业发展迅速,发生了两个大的变化:

  • 大家开始做前后端分离,把静态资源单独管理,好处就不说了,有一个弊端就是当用户浏览器把静态资源下载下来后可能还需要另外一个请求去获取这个页面上的动态数据;
  • 前端工程化的兴起,大家会把 CSS JS HTML 结构统一打包到一个 JS 文件中,HTML 中只有 JS 的引用,这样就导致 HTML 下载完成后还是白屏,只有等到这个巨型 JS 下载完成后首帧内容才开始渲染;

这时就用到了 SSR,通用做法是增加一个 Node 层,在服务器端做首屏内容的拼接,包含静态数据,这样能够保障首帧渲染不仅快,还包含首屏所需要的数据。其结构如下图:

(点击放大图像)

可以看到,Node 这一层在我们界面请求的核心链路上,那么 Node 本身的可用性和上下游的服务相比要差很多,其自身的稳定性需要许多其他工具去保障,那么对于这块业务来说,Node 这一层成为了「核心链路上的可用性短板」,这样即使背后的各个后端系统可用性再好,只要 Node 这一层挂掉就会造成用户无法访问的问题。

所以基于「避免出现核心链路上的可用性短板」这一层考量,我们退而求其次选用「编译预渲染」,在编译期间把首屏结构全部拼装好,这样可用性就得到了保障。

关于 Node 在服务端的应用上,我认为其实大多数情况下,不用要比用要难得多,关于这方面的一些思考可以详见后续文章《服务端为什么不能用 Node》。

理论有了,我们是怎么做的?

「软的」流程规范部分就不展开讲了,各个团队都差不多,只不过是完善不完善的差异。这个部分我主要讲一下「硬的」部分。

前文提到,「硬的」保障主要指的是工程工具的保障手段,工程工具很多,这里对应前文的几大问题顺序讲一讲我们的解决方案。

前端代码可用性部分主要有三个容易出问题的点:空指针、业务逻辑覆盖率、兼容性

「空指针」部分的问题解决只能从语言本身来解决,JS 本身是弱类型动态语言,无法在开发及编译过程中通过工具推导出可能出现问题的点。针对这一点我们从 15 年开始实践 TypeScript ,当时也看了 Facebook 的 Flow ,没有选用 Flow 的原因是当时 Flow 还不够成熟。

引入 TypeScript 后,将我们的弱类型语言编程强类型语言,从编码过程中就可以帮助过滤掉很大一部分空指针问题,TS 强大的类型推导系统可以帮我们分析出系统中的空指针隐患,进而可以解决线上 99% 的空指针问题。当然 TS 还有很多其他好处,这里就不展开了。

(点击放大图像)

「业务逻辑覆盖率」这个问题的背景不再敖述,由于收银台的复杂度高,Case 多,复杂情况下的后端状态很难模拟,因此只能采用自动化工具去解决,这就涉及到了「Web 自动化流程测试」。

Web 自动化流程测试在这种场景下除了可以验证 Case 的正确性以外,最重要的功能就是要有一个异常强大的 Case 管理模块。业界目前并没有理想的工具能够支撑我们的场景。
美大内部有一个我们参与需求的 Web 自动化流程测试工具 「Freekite」,它在 Case 验证功能的基础上,有一个强大的可视化 Case 管理模块。支持复杂的 Case 细分,除了界面操作的细分外,可以全量 Mock 或部分 Mock 后端的数据响应,根据响应拆分出不同的 Case 分支。除此之外,还包含智能自动化断言功能,断言基本不需要人工参与。

可能有人要问了,这个 Case 录完以后万一遇到界面改版怎么办?没关系,虽然有强大的相似度匹配功能,Freekite 还支持单独节点的重新录制,也就完美的解决了 Case 的维护问题,大幅度减少工作量增强效率。紧接着我们会在项目中增加 Freekite 的持续集成,在项目的每一个阶段进行流程上的自动化回归验证,业务逻辑覆盖率的问题就基本解决了。 下图为 Freekite 可视化 Case 管理

(点击放大图像)

「兼容性」问题公司内部有云测平台,可以快速在多机型真机上回归主要流程,可以通过云测平台覆盖占有率 95% 以上的各种机型。然而兼容性也是一样,需要从根本上选用一个可靠的选型,从而避免在处理兼容性问题上会遇到的拆东墙补西墙最后还是不放心的尴尬境地。兼容性问题在移动端除了布局外主要出现在两种操作中,点击和滚动。

前文描述的自主研发的单页视图工具就以最简单的 div 隐藏显示的方式来处理视图切换,使所有元素处于正常的文档流当中,点击处理也通过分级降级的方式最大化平衡体验和兼容性,从而保障了整个项目的兼容性。

静态资源服务可用性主要就是 NGINX 层的健康检查及 CDN 的回源监控,这一点公司 SRE 有强大的系统支持这里不多讲。

网络可用性上最头痛的问题是 DNS 劫持,前文讲到了 DNS 劫持方面除了恶意劫持以外,主要是运营商以节省跨省流量结算费用为目标进行 DNS 劫持。当运营商系统发现 HTTP 访问的域名时会在区域内的服务器中缓存一份资源,后续用户再请求的时候其域名解析会被解析到运营商的服务器上去由运营商的服务器直接返回内容。

其应对方法只有使用 HTTPS ,但并不仅仅是在原有的域名 HTTP 的基础上切换 HTTPS 那么简单,还需要保障这个域名不支持 HTTP 访问并且没有被大范围使用 HTTP 访问过,如果不这样做的话会出现一个问题,运营商在 DNS 解析的时候并不知道这个域名是用什么协议访问的,当之前已经记录过这个域名支持 HTTP 访问后,不管后续是否是 HTTPS 访问,都会进行 DNS 劫持,这是如果使用的是 HTTPS 访问,会因为运营商的缓存服务器没有对应的 SSL 证书而导致请求无法建立链接,这时就会遇到请求失败的问题。在之前业务切换 HTTPS 的时候就遇到了这个问题,请求成功率从 99.96% 降低到了 96%,花了大量的时间去定位问题。当切换了全新的域名后这个问题才得到了解决。

在事后方面,除了强大的支付后台业务系统监控外,公司还有完善的通用监控系统,例如异常监控系统可以分级分批上报前端的 JS Error 及自定义异常,性能监控系统 Performance 可以了解前端的访问情况做性能分析,网络监控系统 CAT 可以快速定位网络层性能状况,区域 DNS 劫持状况等。

以上便是「收银台前端稳定性如何保障?」这个问题我的思考,如有不妥之处欢迎指正。

关于作者

陈禹霖,美团点评前端技术专家,负责金融钱包及支付前端团队。


感谢徐川对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-07-30 17:164631

评论

发布
暂无评论
发现更多内容

智聚北京!相约全球人力资源数智化峰会

用友BIP

人力资源

如何快速使用Redis可视化工具NineData?

数据库小组

数据库 Redis 可视化工具 Redis图形化工具 redis图形化界面 数据库可视化工具

eKuiper 源码解读:从一条 SQL 到流处理任务的旅程

Java你猿哥

Go golang sql ssm eKuiper

IoTLink版本更新V1.25.0

山东云则信息科技

Java 物联网平台

AIGC背后的技术分析 | K均值聚类算法Python实现

TiAmo

Python AIGC K值算法

2023企业数智化财务创新峰会 · 成都站圆满举办!

用友BIP

智能会计 价值财务

周家恩:GaussDB(for MySQL)云原生数据库技术演进和挑战

NineData

MySQL 数据库 GaussDB GaussDB(for MySQL) 华为自研数据库

什么是反射?它有什么用?

javacn.site

Java 面试

Orillusion引擎正式开源!AIGC时代下的WebGPU轻量级3D渲染引擎!

Orillusion

开源 3D 渲染引擎 webgpu AIGC

Django笔记三十之log日志记录详解

Hunter熊

Python django 日志 log

2023-05-17:一个正整数如果能被 a 或 b 整除,那么它是神奇的。 给定三个整数 n , a , b ,返回第 n 个神奇的数字。 因为答案可能很大,所以返回答案 对 10^9 + 7 取模

福大大架构师每日一题

Go 算法 rust 福大大

如何使用Go语言实现迪米特法则

Jack

Java 把一个 List 转换为字符串

HoneyMoose

用友BIP新零售产品发布,与零售企业共创新未来

用友BIP

新零售 数字营销

企业级体验:未来体验管理的价值与趋势

博文视点Broadview

C语言编程—变量的构成

梦笔生花

亚马逊云科技 一周回顾 – 2022 年 7 月 18 日

亚马逊云科技 (Amazon Web Services)

Amazon

ChatGPT 科普(65/100)

hackstoic

ChatGPT

《好好学习》:如何管理知识?

郭明

Spring中@NotEmpty、@NotBlank、@NotNull 区别和使用

Java你猿哥

Java spring Spring Boot string ssm

10个提高工作效率的Cinema 4D小技巧

Finovy Cloud

C4D

开源赋能 普惠未来|浪潮集团寄语2023开放原子全球开源峰会

开放原子开源基金会

开源赋能 普惠未来|360集团寄语2023开放原子全球开源峰会

开放原子开源基金会

浅谈中小企业为何放弃自媒体营销:定位不准、期望值过高、缺乏专业团队

石头IT视角

Golden Gate (GGX) 启动公测,下一代创新DeFi和跨链 dApps 征程开始

股市老人

牛客网最热门的1353道大厂Java面试题整理(附答案)

采菊东篱下

Java 面试

骚操作:使用无头浏览器模拟用户操作进行截图~

王中阳Go

Go 高效工作 自动化 无头浏览器 自动截图

三本菜鸟美团二面被源码暴锤,46天狂学Spring,终入阿里

Java你猿哥

面试 Spring Boot sprnig spring aop spring ioc

美团二面惜败,我的凉经复盘(附学习笔记+面试整理+进阶书籍)

Java你猿哥

MySQL redis Spring Boot 并发编程 JVm虚拟机

实现园林梦想尽在GardenPlanner 激活~

真大的脸盆

Mac Mac 软件 园林设计

什么是Auto-GPT?如何使用、部署Auto-GPT?

炜娓道来程序人生

人工智能 AI ChatGPT

美团点评收银台前端可用性保障实践_语言 & 开发_陈禹霖_InfoQ精选文章