百度MTC 如何建立起一套有效的 APP 监控体系

Rachel · 2016年05月19日 · 最后由 langlang 回复于 2017年06月15日 · 4843 次阅读

概论:
移动 APP 有着自己独特的运行环境和使用场景,相比后端服务,移动 APP 质量同样需要做到可视、可控。移动 APP 是近几年刚刚出现的新产品形态,如何保障 移动 APP 质量是一个新的挑战和话题。今天,我们重点介绍 APP 端问题如何发现、如何定位、如何止损,以及如何建立起一套有效的监控体系,为 APP 稳定应用保驾护航。分为 “端问题概述、端质量监控方案、端监控能力建设” 三个章节。

1 端问题概述
app 客户端产品上线前,会经过全面而且严谨的测试再发布到应用商店。但,发布后产品质量如何,以往更多地依赖于用户的反馈信息。对于较大规模的 app 产品,测试人员无法做到覆盖到全部的手机机型和 ROM。在这种情况下,如何知道一款产品到用户手中的质量呢?此时,需要一套完善的质量监控方案,建立一套牢固的监控体系。这样,对线上产品的 APP 质量问题才能第一时间召回,并做到快速修复。

1.1 常见问题
1.适配问题
客户端测试过程中,测试工程师会覆盖当前比较主流厂商的机型和 ROM,以及市面用户量比较大的 Android/iOS 版本。但,毕竟无法覆盖到市面上所有的机型和 ROM,尤其是 android 系统的手机。所以,用户在下载一款 app 后经常反馈在自己的手机上页面很丑,甚至有的文字重叠,控件位置显示不正确等问题。
举一个实际遇的问题,当 app 上线后收到用户反馈,提到有些页面滑动比较卡顿,容易造成误点击,用户使用的机型是一款比较主流的手机。在获取到用户反馈后,测试工程师马上找到同款手机进行复现,但未复现用户反馈的问题。后来从用户得知复现的手机和用户的手机虽然相同,但是厂商自己定制的 ROM 版本不同,后来通过研究 ROM 代码发现厂商在新版 ROM 中设计了一些新的逻辑处理,会直接导致 app 出现卡顿。研发人员对此做了适配解决了卡顿的问题。此类案例证明,务必对主流手机及 ROM 更新保持较高的质量敏感性,时刻关注厂商升级。快速应变,及时适配到主流机型和 ROM。

2.用户体验问题
通常,产品经理设计产品功能时,考虑得也不一定很全面,往往抱着试错的心态来设计产品,并希望通过用户反馈来得知产品的好坏,以及用户的进一步需求。一旦考虑不周,往往就是取悦一部分用户,同时伤害到一部分用户。举一个实际例子,某一搜索类产品,产品经理为让用户在夜间浏览时有更好的视觉体验,增加了夜间浏览模式的功能。考虑到让用户更方便的设置夜间模式,产品设定为晚上 20 点以后自动弹出一个浮层,询问用户是否设置夜间模式,而且一键即可设定,方便了用户对夜间模式的启用。但,产品经理忽略了一个重要的问题,晚上用户启用夜间模式后,第二天早上如何便捷地切换回白天模式? 而产品并没有在早上也设置一个浮层做一键切换。这样,很多用户在白天也开启了夜间模式,使用体验是很糟糕的。问题在于,切换回白天模式的功能虽然具备,但是入口隐蔽,用户很难找到。从这个问题可以看出,产品体验是设计出来的,需要在用户的实际应用中得到检验。

3.流量问题
当前,中国的 4G 资费相对欧美和日韩目前还是比较高的,同时免费的公共 wifi 覆盖也不高,用户对非 wifi 下的移动流量消费是很在意的。那么,一款移动 app 产品如何利用最少的流量下提供更多的功能?通过客户端缓存是一个常见的技术。举一个实际例子,以小说阅读为例,小说目录一般是罗列很多书籍供用户来选择,这些书籍一般都有书籍名,数据封面图及书籍简介组成。一个页面的数据有 150kb,而且这个页面是小说书单的主入口,所有关于小说的操作都要由这个页面开始。如果用户反复请求这个页面,不仅造成流量的浪费也会给服务端带来很大的请求压力。为此,将这个页面的数据缓存到客户端本地,如果用户在非 wifi 的网络下就不发送请求,如果在 wifi 网络环境下每间隔一定时间去服务端请求一次数据,然后将老数据删除,并将新的数据写到本地,以便用户能够获取到最新内容。这样,不仅解决了流量问题,也解决了一些低配手机本地内存经常不足的问题。从这个问题来看,在产品设计时多从用户的角度出发考虑问题,用户不一定直观地感知到,但实实在在的增加了用户体验,且减少不必要的流量消费,你说何乐而不为呢。

1.2 问题特征
上节介绍了三类常见问题。有些问题是比较容易复现和解决的,也有一些问题相对是有难度的。举几个例子:
场景一:用户反馈在 WIFI 网络下无法发起搜素,搜索结果异常。在 WIFI 环境下复现,无法复现用户反馈的问题,这时往往会归结为网络不稳定造成的。但用户可能当时确实是遇到了问题,这种无法稳定复现的问题,往往归结为偶发性的问题。
场景二:用户反馈离线下载的小说为什么有时候还需要网络。由于用户离线的小说是个连载的小说,当用户阅读完离线的内容后,假设这时候小说有更新了,产品经理为了让用户能够连续的阅读就将产品设计成联网发送在线请求才能继续阅读,这和用户的认知就比较相违背。但,如果用户阅读完已经离线的部分,用户看到书没写完,也会关心为何没有新的内容呢。类似的这种问题归结为长尾问题,需要从产品策略上持续优化来解决。
APP 运行在用户手机端,并且联网到后端服务,许多质量问题也有其自己的独特性。因此,需要通过不同手段,来实现问题的发现、定位和修复。

1.3 面临挑战
对于上述提到的问题,大家可能会问:这些问题该如何发现,对于这些问题如何确定是否做马上修复,哪些问题才算长尾问题?这就是下面将要介绍的线上问题的召回方式和问题影响面的评估。用户反馈是召回问题的一种方式,但是这种被动的召回不足以满足快速召回线上问题的要求,所以搭建一整套完善的监控系统就非常必要了。

1.监控的挑战
对于客户端产品,一旦发布出去就很难有效的控制产品的质量。为此,产品经理和数据分析师往往在产品发布前提出的监控及统计需求,研发工程师开发设计用于监控统计目的的代码,将用户的行为、产品的 crash 等核心质量信息以日志的方式上传到服务端,这些用户所产生的数据就为后续分析产品及质量问题提供了原始的数据依据。

2.影响面的判断
利用客户端上传的用户日志及客户端崩溃信息,进行统计分析。结合线上问题,可进行影响面的评估。影响面评估主要有三类,包括严重问题,特定场景复现问题,不影响主要功能问题。

1) 严重问题一般是要发小版本来修复的问题
2) 特定场景复现问题一般不会发小版本修复,但一定会在下一个版本进行修复
3) 不影响主要功能问题视下一个版本的排期进行修复或删减掉

2 端质量监控方案
由于 APP 载体多种多样,产品质量问题表现形式有很多种。我们以最通用的 APP 为例,总结为以下几种:

  • 来自 APP 产品所依赖的后端服务的问题
  • 来自 APP 产品自身的问题,包括稳定性问题,表现为: 应用 crash(崩溃)、ANR(APPlication Not Responding)、网络错误、请求响应时间长、用户交互不流畅、机型、ROM 适配度不够引起的兼容性问题。
  • 来自 APP 和后端服务之间的链路问题,通 常有:网络问题造成的丢包、TCP 重传等等。 对于 APP 质量监控,可以从三个方向去布局一套完善的监控体系:问题发现、问题定位、问题止损。

2.1 问题发现
由于 APP 受用户机型、手机 ROM、网络环境、用户操作路径差异的影响较大,QA 无法保证在测试阶段暴露所有问题,这就要求我们建立一套线上问题发现体系,及时召回已经交付到线上的移动产品。一套完善的线上问题发现体系,通常来说需要根据产品的核心业务,抽象出核心指标,实现指标量化;制定质量标准,提供实时监控报警。
根据我们的经验,APP 应用的质量指标包括但不局限于:安装成功率,崩溃率,ANR 比例,网络错误比例,请求响应时间等。质量指标与具体的应用功能紧密相关。理论上抽取指标后,如何量化是最关键也是最困难的一步。量化需要有效的问题信息获取途径,日志埋点是一种非常通用的方法,而另外一种途径,用户反馈, 虽然常常被开发者忽略,却同样重要。

2.1.1 用户反馈:海纳百川
一款应用想要在应用市场份额中分得一杯羹,长久地留住用户,需要依赖良好的应用功能和产品体验。用户反馈代表着市场对这款应用的满意度,能够直接反映用户的判断和诉求,也是这款应用迭代改进的第一手资料,前期我们可以通过市场调研等方式获取反馈,但是受限于人力和时间成本,我们很难在用户量巨大的时候复用此法,或者说市场调研始终只能采样而无法全量覆盖。
基于上述,只有提供一个入口,让所有用户的反馈可以如江河入海,汇于一处,我们才能获取到来自不同地域、不同网络、不同机型、不同场景下的用户反馈,进而聚类、分析、改进我们的产品。
用户反馈的通用方法并无太多新奇之处,市面上很多移动应用都会在应用设置页面中附上一个用户反馈的入口,如图 2.1 中百度云和爱奇艺视频的用户反馈界面。


我们必须要明白一点,如今快节奏的生活中,用户愿意提交一个反馈,那这个问题对他/她来说一定是一个很大的困扰,而且他/她又是一个比较忠实的用户,同时对这款应用抱有期待,希望开发者可以改进。所以一旦这个产品开始提供更稳定或者功能更多的收费服务来尝试变现,那么这部分用户会是最大的潜在群体。

一个普通的用户反馈页,却是于细微处见真章的最好实例,这两个页面的设计告诉我们用户反馈的重要原则:
反馈入口路径尽可能短:上述的两个反馈入口都在应用的设备界面,进入反馈页面需要 2 步操作。这一复杂度刚刚好,如果一个反馈需要用户操作 4、5 步才能找到,那么用户的热情会被这种来自技术的傲慢消磨殆尽。
反馈内容的提交成本尽可能低:左侧图片中爱奇艺的用户反馈,不仅事先列出了用户最可能遇到的几种问题,还在页面下方给出了常见问题的 FAQ。不要小看了这一细节,我们可以通过这样的方式,在无形之中完成一次用户问题反馈 + 调查问卷。
对用户的答复应该尽可能的快:如果想要给用户反馈的过程提供更实时的体验,那就要求我们在用户反馈页面完成一个 IM 的功能,这对大多数处于创业阶段的开发者来说并不现实,所以我们建议采用集成插件的方式来达到这一目的。

下面推荐几款常用的用户反馈平台:

1) 美洽,基于 HTML5 开发,只需在 IOS/Android 支持 H5 的浏览器中打开即可,无需安装任何软件程序,代码植入,一步到位,简化沟通流程。
2) Udesk:支持 Android、IOS 以及 APIcloud 三大平台,可以对用户反馈的数据做统计分析,并展示结果。
3) Freshdesk,致力于中小企业网站在线客服技术支持的网站,提供中小企业网站的在线服务质量和用户体验度。

除了在应用中直接反馈,也可以创建用户群(QQ,微信或其他企业级 IM),针对严重问题可以第一时间发现,直接与用户沟通,辅助复现、抓取问题现场信息等,这些对问题的定位和解决是至关重要的。

2.1.2 日志埋点:秣马厉兵
在一个移动应用设计之初,开发者通常考虑的是功能、架构、开发周期等问题,这一类问题通常直接影响应用的发布周期,但是大家往往会忽略一个重要的过程,那就是日志埋点。
为何要埋点
通过用户反馈发现问题毕竟有一定的延时,甚至有一些线上问题会阻塞用户反馈,例如:连续频繁的崩溃,用户反馈模块自身的 Bug 等。要想更迅速及时的暴露问题,需要我们主动出击,获取用户操作的关键信息。

埋点于何处
日志埋点的原则:好的埋点可以达到一夫当关万夫莫开的效果,将所有我们需要的信息通过日志的形式打印出来,选择性或者全量的上传给应用的后端服务,用于支持问题发现或服务改进。
受限于 APP 应用的运行环境,我们不可能在所有的地方进行埋点,笔者在多年的软件开发维护过程中,也见过由于日志添加不当引起程序崩溃问题。

根据自身经验,我们总结出下列日志埋点的建议:
1) 由目标驱动埋点:一个移动应用,开发者或者用户希望了解的服务指标,必须由日志埋点解决;
2) 日志框架通用:应用的第一个版本在日志框架上面花的时间,直接影响后续版本的开发效率。通用和稳定是这个框架必须要考虑的问题。
3) 日志上传:对于已经获取的埋点日志,我们必须考虑它对用户流量及交互流畅度方面的影响——毕竟它的上传使用的是用户网络,尤其是在收费的移动网络下更要慎重。有如下手段可参考:日志压缩和私有协议、用抽样上传代替全量监控;如果日志对时效性的要求不高,可以考虑采用打包整体上传代替实时上传的方式,甚至可以每天上传一次。这些都需要在框架中提前做好部署工作。
4) 日志安全:用户日志中可能包含用户个人信息、用户行为及隐私,一旦信息泄露,可能给用户造成经济、安全等方面的损失,严重影响用户对应用的信任。故日志安全是重中之重,目前行之有效的方法主要有加密和使用安全协议。相对于加密算法较容易被破解的风险,安全协议提供了更严密的保护。目前应用比较广泛的安全协议主要有 https,spdy 等。

2.问题定位
线上问题的快速定位和解决可以直接缩短用户体验受损的时间,通常有以下几种定位思路:
1)日志分析法
当遇到一个问题时,我们最先想到的可能就是查看日志,用户日志是定位问题的最直接的信息来源和方法。日志分析又可以分为两种手段:一是从统计学的角度分析大 量的问题日志,总结聚类,通过其中共性的特征,发现潜在的问题;另一种是针对某个有明确问题反馈的用户,查询其一段时间内的所有操作流程及结果,通过上下 文推测问题原因,也可以辅助线下复现。
当然并不是所有的问题都可以通过用户日志定位,比如日志不全或日志提供的信息并不足以精确定位问题,怎么办呢?那就要求我们能够复现这一问题。

2)问题复现法
通过用户对问题的现象描述,以及已有的用户日志,尝试线下复现。复现时需要关注用户的机型,平台,网络类型,是否设置了代理,甚至是用户所处的地理位置(不 同地域的运营商网络可能有较大差异)等,结合应用所提供服务的逻辑,推测可能出现该问题的原因,尽量增加复现的可能性。

3)推测验证法
当然,APP 的问题很大程度上依赖于当时的问题环境,包括机型,平台,网络情况,手机安装的应用等,都给线下复现带来了巨大的困难。而现有的问题日志又不足 以精准定位。在这种情况下,可以通过问题的现象描述和以有的日志,推测可能的问题原因,埋点监控,通过分级发布的模式,当问题再次发生时,验证哪个推测是 root cause。

4)上下游合作分析
有些功能需要多方合作实现,当这些模块出现问题时,大家通力合作,可能就会离问题的解决更近一步。

3.问题止损
线上问题时时刻刻影响着用户体验,及时止损很有必要。问题止损不仅仅是指定位到了问题的 root cause 从而实现彻底解决,也包括在问题彻底解决之前,如何将对用户的不良影响降到最低。
对于 APP 产品,不能像后端服务那样通过紧急下线/上线补丁解决问题,只能依赖于应用发版,而用户的升级转化也是一个比较漫长的过程。在这种困境中,云端控制和热修复为我们带来了曙光。下面主要阐述云端开关控制的思路。
针对 APP 上影响/风险比较大的功能模块,预先设置好开关,发生问题时,可以通过云端下发关闭指令,及时止损。云端控制是一个概念,实现方式因业务和功能而 异。受限于自身经验,我们无法提供通用的多平台解决方案,但是大道至简,我们希望提醒开发者的是:从代码设计开始,考虑应用、系统、服务三个维度的容灾性。

一个简单的例子:我们可以把功能开关置于一个独立的 Web Server 中,APP 采用轮询或者更加精准的动态策略去访问这个静态文件,当服务某个环节出现问题时,只需要修改 WebServer 中的开关文件,关闭相关功能或者将相应的服务导向备用地址,即可快速的止损。
另外一种方式和上述方案类似,只不过实现的时候不使用访问云端文件,而是由服务端直接向所有 APP 应用下发指令,用于启停某些功能甚至调整某些内部模块的逻辑。这种方式更直接,但是对 APP 的代码的开发提出了相当高的要求:
1) 模块间代码耦合度要极低,从而能够做到动态调整逻辑;
2) 如果云端控制只用于事故止损,那么就要求所有受影响的应用必须保持后台在线或者前台运行的状态。不过具体到当前市场份额最大的几个手机/移动操作系统,我们可以通过推送通知的方式的,尽可能由用户主动唤起应用,借此来获得下发云端命令的机会;
我们建议开发者可以综合考虑应用的代码风格、业务类型、风险类型,来选择某一止损的方案。上述两种方案并非最优解,实际的开发过程中可能需要综合多种方案来达到高可用服务的标准。
同时,目前业界也涌现出一些成熟的解决方案,如 iOS 平台的 APP 动态更新服务 JSPatch(http://jspatch.com) 就是一个专注于此领域的平台,开发者可以试用、借鉴。

3 监控体系建设

3.1 质量标准
1.什么是质量标准:
质量标准是产品生产、检验和评定质量的技术依据。产品质量特性一般以定量表示,例如强度、硬度、化学成分等;所谓标准,指的是衡量某一事物或某项工作应该达到的水平、尺度和必须遵守的规定。而规定产品质量特性应达到的技术要求,称为 “产品质量标准”。--(百度百科)
客户端作为与用户直接与用户打交道的产品,其用户体验是衡量一个客户端的重要部分。用户体验包含了视觉、友好性、易用性等等方面。但是其视觉等方面很难通过量化的方式进行度量。但是产品的核心功能等却是通过一些数据的度量来衡量产品的易用性等。因此,产品的质量标准就应运而生。
在服务类产品中,常用 SLA(Service-Level Agreement)作为衡量产品服务等级的量化指标。按照业务的需求对业务的,对业务的服务指标制定量化的标准,通过量化的标准来衡量和驱动产品的服务越来越好。例如作为 APP 产品中的 crash 率,是衡量一个 APP 稳定性的数据指标,通过对 crash 率的统计数据衡量分析,来保证每个发版的 APP 健壮性得到保障。

  1. 质量标准应如何制定: 质量标准的目的是通过对业务数据的量化与衡量来保证服务的质量,通过质量标准的衡量来推动业务质量变得越来越好。那么应该如何来制定质量标准呢? 根据百度云的经验,质量标准的建立大致总结为:一个核心、三个阶段: 一个核心:时刻以产品线的业务发展为核心 三个阶段:初期阶段、中期阶段和进阶阶段 为什么质量标准的建立要围绕发展来制定。举个例子,比如百度钱包,钱包在初始阶段,其核心的业务指标为发展用户,那么用户的登录,日活等指标为钱包的最核心的指标,当时钱包还没有 APP 端,显然,更不会有 Crash 率等方面的标准。在钱包发展到一定阶段,绑卡用户变成了钱包的另一个核心指标。那么帮卡率变成了业务的核心发展指标。相应的核心质量标准也应该变为绑卡成功率。因此,质量标准的制定一定要围绕业务发展为核心。 在业务发展的不同阶段所设定和采纳的质量标准也是不尽相同的,按照标准由粗到细,量化难度由易到难的阶段一步一步发展而来的。 初期阶段:业务发展的初期或者业务发展到一定的阶段,通过需求或者用户反馈来收集到产品线在发展过程中需要核心保证的 top 功能,这个核心的功能是一个产品生存的支柱,也就是我们需要通过质量标准来衡量我们核心业务提供的服务好坏程度。举个例子,客户端的崩溃情况,是每个产品线所要保证的最基本的质量防线,崩溃率的高低,决定了用户的留存情况,因此,所有产品线都应将崩溃率作为最基本质量标准。而对于不同的产品线,则有各自自身的核心业务指标,比如手百,死链的情况则是关系到用户体验的最核心指标;下载的成功率是百度云用户体验的最核心指标;定位和路线的准确性是地图最核心的用户体验指标。这些也就是各个产品在最初建立质量标准时最关系的方向。

中期阶段:中期阶段,是在初期阶段的质量指标建立完之后,并且在指标的数据获取,指标的计算公式都得到检验之后(尤其是得到 peer 角色的认可),进入到成熟阶段。中期阶段的目标是建立多个完整的子业务质量闭环。客户端的呈现在用户面前的服务能力和用户体验,是每个业务的综合能力体验,对于客户端自身的业务、服务端的服务能力、中间网络抖动情况都密不可分。因此,想要达到一个服务单元的完整质量闭环,必须能 cover 到整个业务链条中的每个质量节点。比如百度云的下载业务,一个完整的下载,从层级上面看,大致分为三个层级:1.APP 自身下载逻辑,主要涉及到下载的重试、并发、容错等 2. 中间业务层, 主要是在下载过程中的下载分发、防盗链、PASS 校验、CDN 回源等等。3. 底层数据拉取,主要是分片数据的重组文件、跨机房的文件拉取等等。所以要完成一个整个下载的质量闭环,必须 cover 整个质量闭环的关键节点, 每个关键节点都会指定相应节点的标准,每个节点的质量好坏的变化,都会在端的质量数据中有所体现。

进阶阶段:进阶阶段是在中期阶段相对成熟之后,针对于业务复杂的每个子业务都能通过服务单元中的核心节点数据来对质量做出评价。进阶阶段,对于每个细节的标准都很全面。任何影响到产品体验,和客户端的运行质量的,都能通过数据分析得到。在中期阶段,有了各个垂类业务的数据,以及在垂类的链条上面的关键节点的数据,能够清晰的知道垂类业务的质量。对于比较复杂的业务,其每个质量节点影响的不单单是一个垂类的业务。在进阶阶段,通过对详细子业务以及子业务之间的关系进行联系与刻画,形成了一张联动的质联网。

3.质量标准的用处:
质量标准的设定主要的目的是通过质量标准的驱动来驱使业务质量变好。质量标准按照覆盖范围来分主要分为两大类:一是通用型,比如 crash 率;二是与自身业务紧密相关的。
1) 质量标准最初级的用处:衡量业务的好与坏。通过量化的手段,对于业务的服务,APP 的运营质量,进行度量。
2) 发现业务中的缺陷:通过对服务单元中的质量数据度量,发现业务质量中的薄弱环节,对于问题的发现和业务的优化提供数据支撑。
3) 业务贡献:通过对质量数据的分析与整合,对于产品策略提供数据支撑和评判。

3.2 能力指标

  1. 数据获取的能力:
    基础数据是质量标准建立的基石,数据获取是一个产品线成熟度的一个标识。一般 APP 的数据获取途径主要有两大类:1. 通用第三方统计平台:例如 mtj 以及一些第三方的数据统计平台,通过提供 SDK 的方式,对 APP 的运行状态等指标进行统计上报,并给出图形化的分析报告。2. 自身业务的数据上报:通过业务埋点或者自己编写的 SDK 捕捉上报。针对自身埋点或者自己编写 SDK 的方式,更加灵活。但是需要投入相应的人力和机器资源。

  2. 数据分析的能力:
    在数据获取的基础之上,数据分析是数据转化成质量数据、质量标准的必经之路。数据分析的过程,是离散的业务数据,通过按照对业务梳理的方面进行划分、统计聚合,变为对业务有用的数据。业务数据的分析的能力集中体现在两个方面:1. 数据计算能力,对于离散数据的计算,需要大量的数据计算才能完成,一套高效、运行流畅的计算框架是对于大数据计算的前提。2. 业务梳理能力,需要对业务的理解和上下游串联有比较细粒度的认识。3. 业务数据分析的能力,对于统计后的数据,能够对应到业务的表现,并能通过数据的变化来预测或者对于平台业务的好坏。

  3. 质量数据的闭环:
    质量数据的闭环是一个比较长期的过程,通过对数据的获取、数据的分析后,得出业务中不合理或者比较薄弱的地方,通过制定合理的优化方案,对业务进行调整优化。然后循环往复来达到质量数据的闭环。

3.3 数据利用
数据分析,是整个监控的最核心,也是难度最大的工作。数据分析,是结合业务的逻辑,通过基础数据进行计算统计后,分析对应到业务逻辑。通过数据的变化,来解释业务的变化与好坏程度。

数据可视化,是数据监控的一个效果展示。好数据展示,能保证用户更好的分析数据的变化与数据直接的内在联系。数据的可视化的重要程度也是不言而喻,其像发动机的润滑油,能够让整个监控体系,更高效,更加顺畅的运转起来。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 5 条回复 时间 点赞

赞,好文。

排版看上去好吃力。

好文章啊

真称得上垃圾排版😑

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册