网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
模拟设备规模
在计算机视觉场景中,我们可能往往要面对大量的设备模拟工作。因为在系统中我们的数据都是从各个摄像设备中采集到视频流,并进行解码抽帧等工作得到图片的。而在这种情况下的性能测试,我们需模拟大量的设备来制造系统压力(上面的场景是模拟结构化数据来制造压力,而这个就是模拟视频流来制造压力)。当然我们不能真的去架设海量的摄像头。所以我们不需要模拟设备,而是模拟视频流就可以了(设备和产品的通信一般都是通过视频流的,比如 rtsp 的实时视频流协议)。
所以我们的解决方案是下面这个样子的:
- ffmpeg这个工具是常用的图像处理工具,我们可以从一个视频数据中提取数据并转成视频流
- 我们建立一个流媒体服务器,把 ffmpeg 转成的视频流推送到这个流媒体服务器中。这样系统就可以跟流媒体服务器进行通信了。这个流媒体服务器可以有很多种实现。我们随便找一个开源的就可以了,比如 easydarwin。
假设我们需要模拟1000路摄像头,那就可以用 ffmpeg + easydarwin 生成 1000个 rtsp 流地址并配置到被测的系统中。当然模拟这么大规模的视频流数据,需要给流媒体服务器相当的资源才可以。
模拟节点规模
在上面的模拟设备规模的场景中,我们往往也需要面对边缘计算系统的情况。因为我们的视频设备往往都假设在靠近用户的地方(原理中心集群),比如路边的摄像头,抓拍机等等。由于我们要面对数据安全,网络带宽和性能等问题,不能把数据传回中心集群处理。所以需要用到边缘计算。
- 云:边缘计算是代替不了云计算的,它与云计算更像是相辅相成的关系。在边缘计算的业务中,仍然需要把部分服务部署在云端中心集群中来控制整体业务的策略。
- 边:部署在每个地域的边缘机房,它们与终端设备距离最近并部署了绝大部分计算服务,接收到终端设备的请求后就开始就地计算并进行实时的反馈。
- 端:终端设备的统称,这些设备可以是手机,可穿戴设备,工厂中的工控机或是路旁的摄像头。它们负责采集数据并传递给距离自己最近的边缘机房进行计算。
它的业务流程可能是下面这个样子的:
我喜欢把这种架构简称为云边端,分别代表了在边缘计算中这3种不同的角色。在计算机视觉场景中,客户的设备可能存在于园区/工厂/学校/社区的摄像头或其他照相设备。这些设备更靠近终端的人而非中心集群,它们收集到图像数据后再经过一系列的处理(解码,抽帧,过滤等)再传输到边缘机房部署的模型服务中进行识别,比如识别人体的行为(打架,离岗,跌倒,野泳等),人体的属性(安全帽,手套,安全带等),又或者识别烟雾火灾人脸对比等等。
完成这样的架构是非常困难的,从物理设施角度看,通常终端设备分布在非常多的地域中,企业需要在这些地域架设大量的机房。而从软件角度看,产品的架构要能够完成所有边缘节点的统一管理,完成机器的区域划分,服务的统一下发以及网络的分发策略等等。
为了支持这种部署架构,人们寻求了很多的解决方案,尤其对当前最主流的云平台技术–K8S 中开发相关功能的呼声尤其强烈。目前国内比较主流的边缘计算项目有 superedge、OpenYurt 和 KubeEdge,他们都是基于 k8s 扩展而来。事实上人工智能产品需要的调度需求会更多,比如对于 GPU、FPGA、TPU 的调度,对于大型存储设备的调度,对于网络流量的调度等等。
所以我们除了要模拟大规模路数的视频流之外,还需要模拟大规模的节点数量来验证集群的性能是否达标。
如果按照传统的思路,测试团队需要申请大量的虚拟机来组建K8S集群,但这无疑是成本非常高的选择,因为在实际项目中我们往往需要测试数百甚至数千台机器规模的集群。所以换一种思路,看一下 K8S 的集群架构:
K8S集群中每台节点中都会启动一个名为 kubelet 和 kubeproxy 的进程。kubelet 负责与 docker/containerD 通信,维护容器状态并周期性的向 APIServer(K8S 集群中的主要服务)上报节点和容器状态,而 kubeproxy 则负责容器网络规则维护。而 APIServer 则会负责把用户创建容器的请求以及 kubelet 上报的容器和节点状态存储在 ETCD 中。
可以看出来API Server是维护 K8S 集群状态最关键的服务,一旦 API Server 出现问题整个集群都会陷入异常状态。而通过上述两点的描述也可以知道随着集群内节点和 Pod 的增多,API Server 承受的压力也会越来越大。
除此之外在商业产品中往往会由于各种需要自研许多组件与 API Server 进行交互,这些组件都会给 API Server 带来不小的压力。所以 API Server 的性能数据往往是测试中最关键的指标之一。业界也会推荐在 K8S 集群中的 etcd 要使用高性能固态硬盘进行部署,因为 etcd 的性能也是影响 API Server 最主要的因素。同时还需要注意的是除了 API Server 以外 K8S 还有一些其他组件也是随着 Pod 数量增长而增加压力的(比如调度器和用户自研 operator)。
所以随着节点和容器的增多,对集群的主要压力在于 etcd 和 apiserver 这些组件。只要我们模拟真实的 kubelet 来上报容器状态给 APIServer 增加压力,那其实是不是有一堆真实的节点和容器并不重要。我们构建一些虚假的 kubelet 就可以达到目标了。
kubemark是一款针对k8s的性能测试工具,它能够使用少量的资源模拟出一个大规模K8S集群。为了演示这个工具需要一个待测试的K8S集群A以及一个装载 Kubemark 服务的 K8S 集群B(也称 Kubemark 集群),当然也可以使用同一个集群装载 Kubemark,只不过在实践过程中我们习惯将待测试集群和 Kubemark 集群区别开来。这时在B集群中部署 Kubemark 的 Hollow Pod,这些 Pod 会主动向A集群注册并成为该K8S集群中的虚拟节点。
也就是说在B集群中启动的Hollow Pod模拟了K8S的 kubelet和kube-proxy 并与A集群的 API Server 进行交互,让A集群误以为这些 Hollow Pod 是真实的节点。这些虚拟节点会完全模拟真实节点的行为,比如它会定时向API Server 上报节点和Pod的状态,也会在用户发起创建 Pod 的请求时进行响应,只不过它不会真的去启动容器而已。也就是说虚拟节点除了不会真的启动容器外,其他的大部分功能都与真实节点差不多。
这样设计的目的是为了能够模拟真实的节点对API Server等组件造成的压力。这样测试人员就可以避免耗费巨额的成本去搭建真实的集群就可以评估 K8S 的性能了。我们可以认为 kubemark 就像是一个复杂的 mock 服务一样,不必启动容器,但可模拟 kubelet 的行为。如图:
大家感兴趣的可以去搜一下kubemark的文档看看它如何使用。
海量小文件的构建
spark 虽然可以控制数据的分片数量,但它无法构建非结构化数据(图片、视频、音频)也无法构建过于庞大的文件数量(比如数亿个文件)。所以我们需要另外一种方法来构建这种量级的数据。通常模拟这样的数据是为了做计算机视觉的模型训练的性能测试,或者测试存储系统本身的性能。构造这样的数据我们要面临的问题:
IO:不管是生成图片,还是文件都会消耗网络和磁盘 io,数亿张图片对于 IO 的考验是比较大的。
CPU:如果按照传统的思路,为了提升造数性能, 会开很多个线程来并发生成图片,计算元数据和数据交互。 但线程开的太多 CPU 的上下文切换也很损耗性能。 尤其我们使用的是 ssd 磁盘,多线程的模式可能是无法最大化利用磁盘 IO 的。
所以我们的主要问题在于如何充分的利用 IO,要尽量的打到 IO 瓶颈。后面经过讨论,最后的方案是使用 golang 语言,用协程 + 异步 IO 来进行造数:
- 首先golang语言的IO库都是使用 netpoll 进行优化过的,netpoll 底层用的就是epoll。这种异步 IO 技术能保证用更少的线程处理更多的文件。关于 epoll 为什么性能好可以参考这篇文章:https://www.cnblogs.com/Hijack-you/p/13057792.html 也可以去查一下同步 IO 和异步 IO 的区别。
我大概总结一下就是,传统的多线程 + 同步IO模型是开多个线程抗压力,每个线程同一时间只处理一个IO。一旦IO触发开始读写文件线程就会处于阻塞状态,这个线程就会从CPU队列中移除也就是切换线程。等IO操作结束了再把线程放到CPU队列里让线程继续执行下面的操作,而异步IO是如果一个线程遇到了IO操作,它不会进入阻塞状态,而是继续处理其他的事,等到那个IO操作结束了再通知程序(通过系统中断),调用回调函数处理后面的事情。这样就保证了异步 IO 的机制下可以用更少的线程处理更多的IO操作。
这是为什么异步IO性能更好的原因,也是为什么异步IO能最大化利用磁盘性能。比如在这个造图片的场景里,我在内存中造好图片后,开始写入文件系统,如果是同步IO那这时候就要阻塞了,直到文件写入完毕线程才会继续处理,但因为我用的异步IO,调用玩函数让内存中的数据写入到文件就不管了,直接开始造下一张图片,什么时候IO结束通知我我在回过头来处理。所以是可以用更少的线程来完成更多的IO操作也就是异步IO能很容易的把磁盘性能打满。我自己测试的时候在自己的笔记本上造100k的图片,大概是1s就能造1W张图片
- 其次golang的GMP模型本身就很高效,编写异步程序也非常简单。我也就花了一上午就把脚本写完了。最后利用 k8s 集群把造数任务调度到集群中,充分利用分布式计算的优势,在多台机器上启动多个造数任务共同完成。
原谅我懒了, 上面这个方案的架构图我实在是不想画了, 大家见谅。
尾声
今天就先这样吧,我了解到的比较典型的,并且比较有技术含量的数据构建场景就这些了。顺便再推销一下我的星球,我会固定更新手把手的教学资料,都是我一个字一个字码出来的,不是网络搬运的。
行动吧,在路上总比一直观望的要好,未来的你肯定会感谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入群: 786229024,里面有各种测试开发资料和技术可以一起交流哦。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**