当前位置:

首页 > 得物客户端直播间APM压测实践

得物客户端直播间APM压测实践

一、背景随着直播行业的飞速发展,越来越多的企业涉足这一领域,直播间的稳定性和用户体验成为了直播平台竞争的重要因素。但是,由于直播间涉及到多个复杂的技术环节,如视频传输、网络通讯、数据处理等,因此直播间的性能压测显得尤为重要。在客户端直播间的压测实践中,APM压测技术是一种常用的性能测试方法,通过对应用程序的性能进行实时监控和诊断,可以快速定位和解决性能瓶颈,提升直播间的稳定性和用户体验。APM压测的重要性检测系统的稳定性:APM压测可以帮助测试人员评估直播间在高并发情况下的性能和稳定性,以确保系统能够正常

一、背景

随着直播行业的飞速发展,越来越多的企业涉足这一领域,直播间的稳定性和用户体验成为了直播平台竞争的重要因素。但是,由于直播间涉及到多个复杂的技术环节,如视频传输、网络通讯、数据处理等,因此直播间的性能压测显得尤为重要。在客户端直播间的压测实践中,APM压测技术是一种常用的性能测试方法,通过对应用程序的性能进行实时监控和诊断,可以快速定位和解决性能瓶颈,提升直播间的稳定性和用户体验。

APM压测的重要性

  1. 检测系统的稳定性:APM压测可以帮助测试人员评估直播间在高并发情况下的性能和稳定性,以确保系统能够正常运行,并且不会崩溃或出现故障。
  2. 提升用户体验:高APM值通常表示直播间可以流畅地处理更多的操作,从而提高用户的体验。如果APM值较低,则可能会导致用户在直播间中遇到卡顿和延迟,影响用户的使用体验。
  3. 发现系统瓶颈:APM压测可以帮助测试人员和开发人员发现系统的瓶颈和问题,从而可以针对性地进行优化和改进。例如,如果在APM压测中发现了数据库读写性能的问题,可以通过升级数据库或者采用其他优化措施来提高系统的性能。
  4. 优化系统性能:通过APM压测,开发人员可以识别系统的性能问题并针对性地进行优化。例如,可以采用负载均衡技术来分散流量,采用缓存技术来减少数据库负载,或者采用异步处理来提高系统的并发能力。

由此可知,APM压测对于保证直播间的稳定性、提升用户体验、发现系统瓶颈和优化系统性能都非常重要。

二、直播间常见的压测方式

  1. 负载测试:通过模拟大量用户访问直播间,测试直播间在高并发情况下的性能和稳定性。可以使用工具如JMeter或LoadRunner等来模拟用户请求,以便评估直播间在不同负载下的表现。
  2. 带宽测试:直播间需要保证足够的带宽来支持高清视频的实时传输,因此需要进行带宽测试以确保直播间具备足够的带宽。可以使用网速测试工具来评估带宽的实际带宽和稳定性。
  3. 性能测试:通过模拟不同场景下的用户访问,测试直播间在不同场景下的性能表现,例如同时观看直播、同时发送弹幕等情况。可以使用性能测试工具如WebLOAD等来模拟并发请求,以便评估直播间在不同场景下的性能表现。
  4. 安全测试:直播间需要保证用户信息和隐私的安全,因此需要进行安全测试以确保直播间没有安全漏洞。可以使用工具如Burp Suite等进行渗透测试,以评估直播间的安全性。
  5. 可靠性测试:通过模拟不同的故障和异常情况,测试直播间在异常情况下的表现和恢复能力。可以使用工具如Chaos Monkey等来模拟异常情况,以评估直播间的可靠性和恢复能力。

综上所述,通过负载测试、带宽测试、性能测试、安全测试和可靠性测试等压测方式,可以全面评估直播间的性能、稳定性、安全性和可靠性,从而确保直播间能够满足用户的需求和期望。

得物直播间主要采用的压测方式是负载测试、性能测试。

三、实现方式

首先我们压测的目标是【基于直播间的IM性能压测】,压测的主要目的是监测当客户端某个直播间长时间接收到大量IM消息的时候,是否会出现卡顿、crash或者OOM等性能问题。在每次发版前跑一轮压测,提前在线下暴露直播间的性能问题,避免性能问题被带到线上。

在具体的压测手段上我们希望能够满足以下几个条件:

  1. 尽量覆盖更多的IM消息类型
  2. 压测自动化程度高,省去较多的手动操作麻烦
  3. 维护成本低
  4. 压测尽量不依赖服务端,能够直接实现本地端上的消息压测

基于上面几点要求,在探索压测的方式,我们直播业务组大概经历了下面三个阶段:

四、压测阶段

4.1   第一阶段

直播间压测的第一阶段采用的方式比较简单,通过脚本模拟用户发送评论、点赞等IM到需要压测的房间。需要自己编写相应的python代码,发送相对应的IM消息到某个直播间,以下是部分Python脚本的部分内容:

class APIUtils:
""" 仅适用于测试环境 """


@staticmethod
def token(user_id: int):
resp = requests.get('https://xxxx.com', params={'user_id': user_id})
return resp.json().get('token')


@staticmethod
def change_rc_im(user_id: int):
try:
im_info = requests.post(
'http://xxxx.com',
headers={'userId': '1'},
data={'kolUserId': user_id}
)
im_id = im_info.json().get('data', {}).get('list', [{}])[0].get('id', 0)
requests.post(
'http://xxxx.com',
headers={'userId': '1'},
data={'kolUserId': user_id, 'id': im_id}
)
except:
pass


time.sleep(3)


data = {
"startTime": int(time.time()) + 1,
"endTime": int(time.time()) + 600 * 6,
"kolUserId": user_id,
"imSwitch": 1,
"id": 0
}
requests.post('xxxx.com',
headers={'userId': '1'}, data=data)


@staticmethod
def get_topic(user_id: int, room_id: int):
""" 获取房间号 """
headers = {
'POIZON-USERID': str(user_id),
'POIZON-ISGUEST': 'false',
'platform': 'iPhone',
'v': '4.78.0'
}
try:
resp = requests.get('xxxx.com',
headers=headers, params={'roomId': room_id})
return resp.json().get('data').get('room').get('imInfo').get('chatRoomId')
except Exception as e:
raise e

主要流程如下图:

得物客户端直播间APM压测实践


这种方式实现的压测比较简单,也能覆盖一些比较重要的IM消息,但是也有几个比较明显的缺点:

  1. 压测某个直播间,需要知道房间的ID或者IM的topic,获取这个信息就要去抓包或者查开播记录,比较麻烦。
  2. 客户端代码每次新增一个IM消息就需要去手动维护python脚本去新加对应的IM号,对于后期的维护有一定的要求,需要维护的同学会写python,并且在后续的需求维护者要主动了解每个版本迭代新加的IM消息,主动去更新脚本的IM消息类型,这一块无疑增加了比较大的维护成本。

4.2   第二阶段

在本阶段着重于解决上个阶段遗留下来的问题,针对获取房间ID的问题,这个只需要后端提供相应的开播列表接口即可,问题是如何使得压测这个流程操作起来更方便?这里我们就想到了可视化,鼠标点一下就能压测岂不是非常简单!于是我们基于前端技术,使用Vue3搭建了一个简易的IM消息操作页面,可以在这个可视化界面选择自己想要发送的房间和IM号,并且在做这个工具的同时丰富了IM消息发送的一些逻辑,可以针对消息优先级、房间消息还是全站消息做了个性化处理,顺便为IM的mock调试做了一些工作。

得物客户端直播间APM压测实践

然后在这个基础上,调接口告诉后端需要压测的房间,再让后端去调用第一阶段的脚本去压测相应的房间。

得物客户端直播间APM压测实践

该方式省去了之前需要自己去手动获取房间ID的麻烦,并且在做这个可视化Mock平台的时候加入了mock IM的功能和压测关系不大,本质上和脚本实现的压测方式并无区别。

4.3   第三阶段

这个阶段解决了上面遗留的随着功能迭代,消息类型覆盖的问题,同时为了进一步解放人工介入,基于Teslab自动化平台,用UI脚本的方式定时去跑我们的压测功能,实现了真正的自动化压测功能。下面分别解释每个步骤的具体操作

4.3.1  消息类型覆盖

在客户端每个IM消息类型,都有一个对应的IM消息Java类,每增加一个IM消息类型,都会有一个实体类去对应,这些类都继承于基类BaseLiveChatMessage,因此我们在BaseLiveChatMessage里面加了一个接口抽象方法,用于产生此消息类型的mock数据。

得物客户端直播间APM压测实践

那么我们在新加IM数据的时候,继承BaseLiveChatMessage,就需要强制覆盖这个方法,去生成自己的mock消息,非常好的解决了维护性的问题,因为不覆盖这个mock方法是无法通过编译的。

下面是警告消息和抽奖消息的Mock代码:

得物客户端直播间APM压测实践

得物客户端直播间APM压测实践

有了上面的基础,在测试工程里面加一个IMTest测试类,主要逻辑是扫描所有继承BaseLiveChatMessage类的子类,然后反射构造函数,调用mock接口即可获取到相应IM类的mock消息实体,伪代码如下:

//获取BaseLiveChatMessage子类
if (allSubClass == null) {
allSubClass = ClassUtils.getAllSubClass(BaseApplication.getInstance(), BaseLiveChatMessage::class.java)
val iterator = allSubClass?.iterator()
while (iterator?.hasNext() == true) {
val next = iterator.next()
try {
next.getDeclaredMethod("mock", Int::class.java)
} catch (e: NoSuchMethodException) {
}
}
}
// ....
allSubClass?.forEach {
val o = constructorMap[it]?.newInstance() as BaseLiveChatMessage
var message: BaseLiveChatMessage? = null
message = o.mock(0)
justPostIM(message) //发送IM
}

之后的压测就是控制发送频率、压测时间即可实现本地的压测,无需依赖服务端实现。

得物客户端直播间APM压测实践

到此为止,基本已经解决了文章最开始的几个问题,IM消息的覆盖率和可维护性也得到了保证。

4.3.2  自动化

在现有的基础上,为了使得压测更加自动化,我们接入了Teslab自动化测试平台,可以定时启动自动化UI脚本,提升压测效率,自动化脚本是基于UiAutomator,语法非常简易,维护成本很低。

得物客户端直播间APM压测实践

  1. 客户端内部备齐所有的IM压测类型。在进行IM压测时,客户端应当支持各种类型的IM消息,例如文本消息、语音消息、图片消息、礼物消息等等。同时,客户端还应当支持各种不同的IM操作,如点赞、评论、送礼等,以全面测试IM功能的稳定性和性能。
  2. 直播debug工具接通了kylin,kylin组件已经打通了amp平台。为了更好地收集和记录压测指标,我们需要将直播debug工具与kylin组件和amp平台进行打通,确保能够快速地收集和分析压测数据。在这个过程中,kylin组件将负责接收客户端发送的压测数据,并将这些数据传递给amp平台进行进一步处理和分析。
  3. apm平台收到了直播IM压测记录飞书通知到固定的群。为了及时发现和解决潜在的性能问题,我们需要将压测记录及时通知到相应的人员,例如开发人员、测试人员等。在这个过程中,我们可以利用飞书等即时通讯工具,将压测记录发送到固定的群,以便相关人员及时查看并进行分析。

综上,第三阶段的压测策略通过客户端发起的方式,实现了IM压测使用方式方便、支持多设备压测和压测指标有记录的目标。同时,我们还需要在实际实施过程中不断优化和改进,以进一步提高压测效率和结果的可靠性。

压测流程图:

得物客户端直播间APM压测实践

五、压测效果

得物客户端直播间APM压测实践

六、收益

压测只是一个手段,最重要的是发现问题,解决问题,通过三个阶段的压测也发现了不少问题。

通过三个阶段的压测,团队成功地发现并解决了一些iOS方面的问题。其中,最重要的是发现了压测时长超过20分钟时,CPU异常高并伴随着界面卡死的情况。经过排查,发现问题源于消息逐条往业务层分发,导致CPU消耗太大和UI界面刷新太频繁(每秒钟刷新大几十次)。针对这个问题,团队采取了两个解决方案:一是通过定时器向业务层分发消息组,而不是逐条分发消息;二是在定时器内部做线程切换,保证在一段时间内只有一次的线程切换。

此外,团队还在压测过程中发现了内存持续上涨产生的OOM情况,原因是某些IM有动画执行时间,一段时间内只会执行一次,高并发情况下就会不断累积导致内存溢出。对于这个问题,团队采取了对动画执行的优化方案,避免了内存溢出的情况。

另外,通过kylin组件,团队还发现了若干内存泄漏问题,并及时解决了这些问题,保证了直播应用的稳定性和可靠性。总之,通过三个阶段的压测,团队成功地发现和解决了多个问题,不仅提升了应用的性能和稳定性,也为团队的技术积累和发展提供了有益的经验和启示。

七、结束语

性能压测的确是保证直播间稳定、高效运行的重要手段,但我们不能把它看作是代码开发的终点。好的代码应该是能够被整个团队共同维护的,代码的可读性、可维护性和可扩展性同样重要。只有在开发和维护过程中,不断注重代码质量和团队协作,才能让直播间持续地为用户提供优质的服务。

在进行直播间性能压测的同时,也需要关注代码的可读性和可维护性。我们应该建立严格的代码审核机制,对代码质量进行监控和控制,以确保代码的可靠性和可扩展性。同时,注重团队协作,建立团队内部沟通和合作的机制,让团队成员能够共同维护好直播间,提供更好的用户体验。


本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
相关文章 更多
using namespace 使用中遇到的问题怎么解决
using namespace 使用中遇到的问题怎么解决

命名空间的基本概念与常见引入问题在C++等编程语言中,命名空间(namespace)是一种将代码标识符(如变量、函数、类名)封装在特定名称下的机制,其主要目的是避免命名冲突,尤其是在大型项目或使用多个第三方库时。使用“using namespace”指令可以将指定命名空间中的所有名称引入当前作用域,

c语言函数递归 实操经验总结:这些技巧很实用
c语言函数递归 实操经验总结:这些技巧很实用

理解递归的基本原理在C语言中,递归是一种函数调用自身的编程技术。要掌握它,首先需要理解其核心思想:将一个复杂的大问题,分解为一个或几个与原问题相似但规模更小的子问题,直到子问题足够简单,可以直接求解。这个过程通常包含两个关键部分:递归出口和递归体。递归出口定义了问题何时不再继续分解,即最简单、可直接

c语言函数递归 怎么选?常见方案对比分析
c语言函数递归 怎么选?常见方案对比分析

递归函数的基本概念与适用场景在C语言编程中,递归是一种函数调用自身的编程技巧。它并非适用于所有问题,但在处理某些具有自相似结构的问题时,能提供极其清晰和优雅的解决方案。递归的核心思想是将一个大规模问题分解为一个或多个同类型但规模更小的子问题,直到子问题简单到可以直接求解。典型的适用场景包括树形结构的

Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解
Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解

理解内存管理的基石在Objective-C的编程世界中,内存管理是开发者必须掌握的核心技能之一。它直接关系到应用的性能、稳定性与资源利用效率。与一些采用自动垃圾回收机制的语言不同,Objective-C在很长一段时间里,依赖一套基于引用计数的、需要开发者部分介入的管理规则。这套规则的核心思想是明确的

如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏
如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏

理解 dealloc 的角色与时机在 iOS 应用开发中,内存管理是保障应用性能与稳定性的基石。dealloc 方法是 Objective-C 中对象生命周期结束时的关键回调,它标志着对象即将被系统回收内存。正确理解其触发时机至关重要:当一个对象的引用计数降为零时,运行时系统会自动调用该对象的 de

深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制
深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制

内存管理的基石在Objective-C的世界里,内存管理是开发者必须掌握的核心技能之一。作为一门在手动引用计数(MRC)时代诞生的语言,Objective-C要求程序员对对象的生命周期有清晰的认识。dealloc方法正是这一生命周期中至关重要的终点站。它是一个实例方法,当对象的引用计数降为零时,系统

理解 native2ascii:Java 国际化开发中的字符编码工具
理解 native2ascii:Java 国际化开发中的字符编码工具

native2ascii 工具的基本定位在Ja va应用程序的国际化与本地化开发过程中,处理非拉丁字符集是一个常见且关键的环节。Ja va内部使用Unicode字符集来统一表示全球各种语言的文字,但其属性文件(.properties)在历史上要求使用ASCII编码,或者更准确地说,要求非ASCII字

如何使用 native2ascii 转换中文字符为 Unicode 转义序列
如何使用 native2ascii 转换中文字符为 Unicode 转义序列

理解 native2ascii 工具的基本用途在软件开发,特别是涉及国际化处理的场景中,开发者常常需要处理不同编码的文本资源。native2ascii 是 Ja va 开发工具包(JDK)中提供的一个命令行实用程序,其主要功能是将包含本地字符编码(非ASCII字符)的文件,转换为包含 Unicode

Java native2ascii 命令详解:解决属性文件乱码问题
Java native2ascii 命令详解:解决属性文件乱码问题

native2ascii 命令的由来与作用在Ja va开发中,处理国际化资源文件是一个常见需求。资源文件通常以.properties格式存储,用于支持多语言界面。然而,Ja va属性文件默认采用ISO-8859-1字符集编码,这导致了一个直接的问题:当文件中包含非拉丁字符(如中文、日文、韩文等)时,

一个 memwatch 实战案例:定位野指针问题
一个 memwatch 实战案例:定位野指针问题

内存监控工具的价值与挑战在软件开发,尤其是使用C/C++这类手动管理内存的语言时,内存错误是程序员最常遭遇的难题之一。其中,野指针问题因其隐蔽性和破坏性,往往成为最难定位的“幽灵”缺陷。它可能潜伏在代码中,在特定条件下才被触发,导致程序崩溃、数据损坏或难以预测的行为。传统的调试手段,如打印日志或使用

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。