叨叨
赛题
赛题背景
基于公共云构建产品、系统和应用已经是当前最热门的技术趋势了,公共云不仅提供了非常丰富的基础设施资源类型,如服务器、网络、存储和数据库等资源,还为这些资源提供了极高的可靠性保证,综合性价比非常有竞争力,尤其是阿里云发布的第七代云服务器ECS,搭载最新一代英特尔®至强®可扩展处理器(代号Ice Lake)以及阿里云自研的第三代神龙架构,可以更好地满足各种类型的计算任务。本赛道将基于这款云服务器进行,希望通过此次比赛可以更具体更全面地展示其性能。
Web Services是各行业中最为常见的软件系统之一,本赛题探讨Web Service在云上部署的性能优化,希望参赛者通过代码撰写、操作系统与数据库选型、各种参数调优等手段,优化云端Web服务的性能和保障服务的高可用。
赛题描述
构建一个高性能、高稳定的Web Service,具体形式是实现一个在线实时聊天室Web Service。
该服务需要完成以下功能,下文将以部分API方式进行说明:
用户注册、用户登录等。
创建房间、查看房间等。
用户进入、退出实时聊天房间,每个用户只能进入一个聊天室,进入某个聊天室时,会自动退出上一个聊天室等。
用户发言和实时收取其他人的消息。
注:聊天室、消息和用户,三个数据必须持久化;在线人数无须持久化。
完整API Spec请参考这里。
复赛要求如下:
1.所有的数据持久化都必须是集群化(3台机器)的,任何一台机器宕机,其他的两台机器应该能继续对外提供完整的数据查询和插入服务。
2.在任何一台机器上登录和进入聊天室,其他的机器都应该有相同判断,即该用户登录以及进入聊天室。
3.程序在机器启动后,会收到请求/updateCluster的post请求,body是三台机器的ip的list,比如 [“192.0.0.1”,”192.0.0.2”,”192.0.0.3”]。
4.经过上面的步骤等待一分钟后,会收到/checkCluster的GET请求,需要返回http status 200,然后开始集群测试。
环境要求
操作系统:任意阿里云的官方镜像,任意Windows或Linux、OS。
编程语言:任意语言,Java/Go/Python/JS等。
数据库:任意数据库,MySQL/Redis等。但所有数据必须落盘,即使实例重启,也不允许丢任何数据。
提交说明
最终的产出以zip包形式(不得超过100M)提供,zip包里面需要包括以下内容:
可部署的二进制文件,或代码,如python。代码必须有一个良好的规范,建议参考所选编程语言的通用规范。
部署脚本。
环境配置,以资源编排ROS模板展示。
参考示例zip包结构。
评测系统收到提交的任务后,将会:
安全扫码,如发现病毒或可疑代码将直接取消比赛资格,作废任何已有成绩。
解压zip示例中的deploy_application.zip 。
使用ros json 模板进行ECS环境部署,参考注释,可能需要调整镜像ID。
系统自动将deploy_application.zip包下载并解压到目标目录。
调用deploy_application.zip里面的start.sh来启动service。
部署完成以后将会开始评测,请使用端口8080。
请参考示例git repo 2021-contest/demo/build下的zip包。
评判标准
评测分为两个阶段:分别为完成性验证阶段和性能测试阶段。
完成性验证阶段,需要满足综合任务描述与环境要求中提到的数据落盘、数据持久化等要求(复赛环节注意新增要求),否则最终得分为0。
性能测试阶段,通过接口完整性、API的QPS、API的延时情况,在选手提交zip包之后,计算性能测试的综合得分,其中:
1、接口功能越完整正确,得分越高。
2、综合API的QPS,QPS越高,得分越高。
3、综合API的延时,延时越低,得分越高。
计算性能测试的综合得分=n*10+50*(qps/10000)*k+50*n∗10+50∗(qps/10000)∗k+50∗(1/time_deplay)*m。∗m。
其中,n为评测的接口个数,k是需要进行评测qps的接口个数,m是需要评测的延时接口个数。
评测流程
参赛者提交的服务,最终将部署在搭载最新一代英特尔®至强®可扩展处理器(代号Ice Lake)阿里云第七代ECS实例,4核8G (规格)上。
评测系统将对该服务进行压测,压测时会使用多个场景进行压测,且场景可能会发生变化,但是都会是多个API的组合。
大赛更多细节,包括API Spec、Demo和zip包示例,请参考以下链接,将持续更新:
https://code.aliyun.com/ecs-contest-support/2021-contest/tree/master 。
解题思路(声明:以下所有的测试均在阿里云4c8g的ecs环境下进行)
- 先使用
spring-boot
快速写了一个baseline 的东东,把题目的样例都跑过了,结果:api是满分190,性能分数只有0分
。然后拿wrk 压测发现tps=1K
左右,然后就尝试写了一个返回字符串的方法去压测,最后拿到报告只有tps=5K
这样子。spring-boot 原来这就是你的极限了🐴,垃圾(小声BB,于是接下来就开始专注性能这块了。 - 我调研了一下,所有人都在吹
vert.x
的性能有多好多好。fine!那就搞起吧,社畜狗一边加班一遍肝vert.x
,终于在看了2天文档,写了个demo 出来。然后故技重施又:写了一个返回字符串的空方法去压测,发现效果喜人,直接将tps的值拉到一个新高度 tps=100000+
,是的,xdm你没有听错,性能提高了接近20倍,这个还是在我辣鸡的macbook上面压测的结果,我尝试在阿里esc
上面进行jvm预热
后再压测,tps达到了恐怖的130000
,就是这么强!!那妥了,天命人就是你了-vert.x
! - 啪啪啪,一顿拍完,效果还不错,
tps=100多分了,总分300+还可以了
,换框架的收益可以说是十分明显。然后一看排行榜发现居然有大佬居然有700+分,看来还是有很大的提升空间, - 于是我开始尝试:
对查询的接口加上缓存
,对查询的各个点进行优化,如果查询命中就放到缓存中,如果没命中就放入一个无效值,避免下次还去查询数据库,缓存使用guava 的 Chche实现,使用LRU策略淘汰
。发现效果果然不错,总分冲击到了400+
,查询的tps 查询也达到了100000+ - 接下来,查询的优化完毕,就开始优化插入的接口。借鉴批量处理的思维:
将数据库的插入操作,从单条插入修改成了多条异步插入
,主要的设计思想呢:就是将需要插入的任务扔到队列里面,然后搞一个定时任务定时处理任务队列里的数据,进行批量插入。我设置的定时任务间隔是30ms,相当于实现了一个简单的生产消费模型
,具体代码可以查看异步插入和定时任务消费,这边将tps 提升了几倍,最后测试数据库写入的接口tps达到了47000+
- 接下来就是对数据库参数进行调优,我这边数据库用的是
postgre-sql
,然后发现对数据库参数调优其实没啥作用(还做了各种数据表分区,表sharding的处理,一顿操作猛如虎,2333)然于是到此分数就定格到了519.94
,初赛14名,说实话不是什么出彩的好成绩,只是分享给大家看一乐呵 - 当然成功进入复赛,但是那段时间社畜需要996没时间搞比赛,所以复赛就没打了
- 就介样儿吧,拜拜