python sanic openapi_基于 sanic 打造 python web 框架

0x00 Why

为何做这件事,在去年的一个项目中,算法同学要使用在线模型训练,不得不使用python的tf框架,这样我们不得不是python web框架,当时因为团队里面没人懂python相关的知识,只是简单的用tornado搭建的一个。但是在后期使用过程中,压测发现了tornado在低耗时的接口不够稳定,波动比较大。我们的接口一般20ms,但是经常波动到40ms,并发其实也不大。所以经历了痛苦过后,为了满足后续类似的场景,我们需要打造一款内部使用的python web框架,能够支持低耗时接口的稳定性,以及稍微性能强点。

0x01 How

基于以上的出发点,开始调研python web相关性能比较高的框架,看到了sanic。说是性能比较高。先看下sanic作者开发sanic的动机,是因为他看下了下面这篇文章:

是因为python3.4推出了asyncio,解决令人诟病的异步io性能问题,3.5后推出了uvloop,基于libuv,libuv是一个使用C语言实现的高性能异步I/O库,uvloop用来代替asyncio默认事件循环,可以进一步加快异步I/O操作的速度,而tornado在python3中还没有使用uvloop。

首先来看下uvloop的性能表现:

0x02 tornado vs sanic

口说无凭,直接压测看数据,我们同时构造两个框架的一个接口,接口里面没有任务逻辑,就是简单的返回一个helloworld,都是起一个进程,实测的数据

sanic:18000/s

tornado:5000/s

就框架本身而言,sanic确实性能高。然后我又对各个耗时阶段的接口进行压测,来判断不同耗时,两个框架的表现。

Sanic Sleep(ms)\Thread

1

10

50

100

1

1-3之间波动,波动范围为0%~300%,周期性的

1-6之间波动,波动范围为0%~600%,周期性的

1-11之间波动,波动范围为0%~1100%,周期性的

1-7之间波动,波动范围为0%~700%,周期性的

10

11-15之间波动,波动范围为10%~50%,周期性的

12-17之间波动,波动范围为20%~70%,周期性的

11-20之间波动,波动范围为10%~100%,周期性的

11-31之间波动,波动范围为10%~310%,周期性的

50

51-56,周期性的波动

54-60,周期性

54-71,周期性的

51-61,周期的

100

101-106之间波动,波动范围为1%~6%,周期性的

103-110之间波动,波动范围为3%~10%,周期性的

103-120之间波动,波动范围为3%~20%,周期性的

105-130之间波动,波动范围为5%~30%,周期性的

Tornado Sleep(ms)\Thread

1

10

50

100

1

2-4之间波动,波动范围为200%~400%,周期性的

6-11之间波动,波动范围为600%~1100%,周期性的

21-56之间波动,波动范围为2100%~5600%,周期性的

50-106之间波动,波动范围为5000%~10600%,周期性的

10

11-15之间波动,波动范围为110%~150%,周期性的

11-18之间波动,波动范围为110%~180%,周期性的

28-43之间波动,波动范围为280%~430%,周期性的

62-104之间波动,波动范围为620%~1040%,周期性的

50

52-57之间波动,周期性的

54-62,周期性的

51-80,周期性的

53-75,周期性的

100

101-108之间波动,波动范围为1%~8%,周期性的

101-111之间波动,波动范围为1%~11%,周期性的

101-111之间波动,波动范围为1%~11%,周期性的

101-140之间波动,波动范围为1%~40%,周期性的

result

sleep 1ms&100个线程压的情况

Sanic波动为1-7ms,而Tornado已经最低到50ms,最高飙到100多ms,显然在10ms以内的接口,并发超过50的,不适合使用Tornado,推荐使用Sanic,Sanic赢一局,Sanic1:0Tornado

sleep 10ms &100个线程压的情况

Sanic波动为11-31ms,而Tornado已经最低到62了,最高到100多毫秒,显然在100毫秒内,并发超过50的时候,还是Sanic更胜一筹,Sanic再赢一局,Sanic2:0Tornado

sleep 50ms&100个线程压的情况

Sanic波动为51-61,Tornado为53-73,两个框架之间差别不大,建议使用Sanic,Sanic3:0Tornado。

sleep 100ms & 100个线程压的情况

Sanic波动为105到130,Tornado波动为101-140,选择谁都可以。这次打个平手Sanic2:0Tornado

综上所述,sanic性能确实优于tornado。所以新框架采用sanic来开发。

0x04 框架设计

log库:传递logid和自我生成logid,且能支撑多进程,不丢日志的情况。

redis库:拥有连接池,

mysql库:拥有连接池。

python版本库管理要简单,易发布,易部署。

要有利用新框架新建项目,更新框架的工具,不用用户每次自己下载然后copy,改名。

基于以上的设计,调研了一下用到的库。

sanic

python3.7+

sanic最新版

redis

redis-py:官方推荐,配合hiredis-py会得到性能的极致提升。

mysql

pymysqlpool:mysql连接池,包装pymysql提供连接池的功能。

还可以使用pymysql+dbutils自己编写连接池的代码。

config

配置文件支持ini格式的,保持跟go的一样。

ConfigParser

官方使用py的配置文件,采用该方式更方便。

logging

日志库要有logid

sanic自带有log库,使用的就是python自带的基础库logging。

concurrent-log-handler只支持日志大小滚动,不支持时间滚动。

目前python最吃香的log库是loguru,我们也集成了,该库支持多线程,虽然不是进程安全的,但是也有方式支持多进程log。

需要对比下这两个库在sanic下性能,选择一个最优的。

logging(logging.handlers.TimedRotatingFileHandler多进程丢日志)

logging(concurrent-log-handler),带了进程锁以后严重影响了框架性能.

loguru

对于高qps的场景下,可以让其丢日志,使用普通的TimedRotatingFileHandler。对于qps要求低的场景,建议使用concurrent-log-handler保证多进程下日志不丢失。

python依赖包管理

python项目迁移

click构建命令行工具

利用click开发。一条命令就能新建一个新的项目,直接可运行。

框架性能

目前框架开发已经完成,内部已经发布了第一个版本,对该框架的性能也进行了一个压测。

sanic空逻辑性能测试(只返回一个json串)

1个线程压1个进程qps:6000

1个线程压2个进程qps:6600

2个线程压1个进程qps:10000

4个线程压1个进程qps:9600,单进程支持4个并发时出现瓶颈。

单进程处理能力比较强,建议优先单进程

2个线程压2个进程qps:11000

4个线程压4个进程qps:13000

8个线程压8个进程qps:14000

16个线程压8个进程qps:13000,瓶颈出现

sanic加入log测试(打印一条log到文件,多进程不丢日志,启用进程安全的log)

1个线程压1个进程qps:1500

1个线程压2个进程qps:1300

2个线程压1个进程qps:1900

4个线程压1个进程qps:2100,但是耗时已经上来了。

2个线程压2个进程qps:2000

4个线程压4个进程qps:2400,耗时已经增加许多,瓶颈

8个线程压8个进程qps:2600,耗时增加。

16个线程压8个进程qps:2800,耗时已经飙升了。

sanic加入log测试(打印一条log到文件,多进程丢日志,不启用进程安全的log)

1个线程压1个进程qps:3200

1个线程压2个进程qps:2200

2个线程压1个进程qps:4800

4个线程压1个进程qps:4800

2个线程压2个进程qps:4000

4个线程压4个进程qps:5200

8个线程压8个进程qps:4400

sanic加入redis性能测试

redis(set)操作,1个线程压1个进程qps:3700

redis(set)操作,1个线程压2个进程qps:3200,反而降低了。

redis(set)操作,2个线程压1个进程qps:4700

redis(set)操作,4个线程压1个进程qps:4600,单进程出现瓶颈。

redis(set)操作,2个线程压2个进程qps:5500

redis(set)操作,4个线程压4个进程qps:8100

redis(set)操作,8个线程压8个进程qps:8000,下降,瓶颈

redis(set)操作,16个线程压8个进程qps:8300,瓶颈

Redis稳定性较好,且增加线程或者进程呈线性增长,直到到达瓶颈。且尝试增加服务能力的时候,最好是起和并发量一样的进程数,不然来回切进程反而会降低qps。

压测结果分析

建议采用单进程,开启普通log,无包装多进程安全的log。

最后我们测试了下4个线程压一个进程,打印一条log(普通log),set一次redis的业务,qps:3200

在不要求日志不丢的,耗时可以放宽的情况下,可以提升进程数来提升性能。

0x05

虽然sanic框架性能很好,但是python自身的性能,以及python库的一些影响,仍然不能达到go的性能。但是应付一些中小型项目是可以了。后面持续优化,有机会开源出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值