热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

记一次tornadoQPS优化

本文最早发表于个人博客:Pylixm’Wiki应项目的需求,我们使用tornado开发了一个api系统,系统开发完后,在8核16G的虚机上经过压测qps只有200+。与我们当初定的

本文最早发表于个人博客:Pylixm’Wiki

应项目的需求,我们使用tornado开发了一个api系统,系统开发完后,在8核16G的虚机上经过压测qps只有200+。与我们当初定的QPS 大于2k差了一个数量级,于是便开始了漫长的优化之路。在优化过程中,学了许多东西,有必要整理记录下备查。

我们的技术选型:

  • python2.7
  • tornado4.4.3
  • sqlalchemy1.1.5
  • mysql5.6
  • rabbitmq

当初技术选型的时候选择tornado,便是因为其优秀的性能,这么低的QPS自然是不甘心。究竟tornado可以达到多少QPS呢?于是编写了简单的hello world,在上边的虚拟机中起16个进程下,使用ab压测QPS竟然达到了惊人的6K,平均响应时间在毫秒级。这下有信心将api的QPS继续优化了。

初步分析

提升QPS, 可从两方面入手,一个是增加并发数,其二是减少平均响应时间。从目前情况看,增加进程并发数是最直接的手段,但当达到机器资源的瓶颈时,可靠堆叠机器来解决。那么
相比较下,减小平均响应更为重要。初步分析了我们开发的api,平均响应时间在几百毫秒级别。大部分的时间花在系统与数据库的交互上,到这,便有了一个优化的主题思路:最大限度的降低平均响应时间。

我们API完成的功能为,接受请求参数做一些列的认证判断(与数据库交互),将消息以广播的形式发送到rabbitmq供消费者消费,最后返回给客户端发送结果。根据此逻辑,影响响应时间的地方,分析如下:

  • 与mysql 数据库的交互
  • 使用rabbitmq广播消息时的时间耗费
  • 耗时的业务逻辑代码片段

优化思路

根据上边的问题,从以下几个方面入手:

  • 增加tornado的异步特性
  • 分析与数据库的交互,减少与数据库的交互时间
  • 分析rabbitmq的时间耗费,减少发送信息时间
  • 优化业务代码逻辑

具体实施

tornado 的异步特性

开发api时,因为对tornado 的异步特性不是很熟悉,便没有使用。后来随着测试的深入,发现需要使用后,开始了解。
随着了解的深入,发现tornado是并没有很好的支持数据库的异步特性,更多是对网络的异步,官网上也是写的”网络非阻塞框架“。
查阅官方文档,tornado的异步实现,见官方文档
总的来说,使程序异步的方式有3种,参考这里。如下:

  • 第一种,使用tornado 的 gen.coruntine。

    使用此种方式,需要异步数据库的驱动库,经查找现阶段并没有很好的成熟的支持异步查询mysql的python驱动,放弃此种方案。

  • 第二种,使用tornado 的线程模块。

    此种方式比较方便,只需要在耗时的函数上添加装饰器即可,简单方便,可以说是一种万能方案,但此方案耗费系统资源。
    系统资源并不是我们的瓶颈,我们最后采纳了此种方式。

  • 第三种,使用外部队列,单独其worker 进程或线程去处理。例如,celery 等。

    此种方式增加了外部的依赖,增加了系统的复杂性和后期的维护难度,放弃此种方案。

增加了异步特性外有显著的提升。

mysql 数据库的优化

数据库方便,我们适用的是SQLAlchemy。使用ORM时,在减少裸sql带来的查询复杂度的同时,必然会增加查询数据库的耗时。我们也做过测试,
使用pymsql链接mysql,直接使用裸sql查询与使用sqlalcemy 的对象查询的耗时差别有7、8个毫秒的时差,与sqlalchemy的裸sql方式执行时间几乎一致。
可见,sqlalchemy的orm方式是有一定时间耗损的。stackoverflow的一个问题,也验证了我的想法,见Why is loading SQLAlchemy objects via the ORM 5-8x slower than rows via a raw MySQLdb cursor?

针对数据库方面,我们做了如下优化:

  • 将SQLAlchemy 查询改为核心裸sql方式,可参考这里。
  • 优化数据库,增加必要的索引。
  • 将逻辑中的过滤条件,尽量的移到sql中,减少sql结果集的大小,加快查询速度。
  • 将可以单词查询出的数据集放到一次查询中,减少链接数据库的次数。

分析rabbitmq的时间耗费,减少发送信息时间

rabbitmq 方面,使用的是pika 作为驱动库连接的,使用方式是每次发送数据的时候创建链接和通道,发送完毕后立即关闭链接。考虑到是否可以使用长链接,创建链接后不关闭,只关闭channel。修改后发现报错,具体代码如下:

# -*- coding:utf-8 -*-
import pika
from settings import settings
class Client(object):
def __init__(self, host, port, username, pwd):
self.host = host
self.port = port
self.username = username
self.pwd = pwd
self.init_connection()
def init_connection(self):
user_pwd = pika.PlainCredentials(self.username, self.pwd)
self.cOnnection= pika.BlockingConnection(pika.ConnectionParameters(
host=self.host, port=self.port, credentials=user_pwd))
# ...

补充错误材料分析 – todo

翻阅了pika的文档,发现其有异步的使用方式,且有与tornando 框架的结合的实例,见文档。
pika的异步方式,使用了和tornado 相同的基于epull的事件循环模型,如何将其与tornado 的IOloop结合是个问题,
其有个tornado的链接适配器,翻看其代码还是有些不太明确如何使用,有时间的时候再继续研究下。

针对rabbitmq的优化我们放弃了,但优化过程中有些值得分析的文章,整理如下:

  • rabbitmq-amqp-channel-best-practices
  • rabbitmq-best-practices-for-designing-exchanges-queues-and-bindings
  • tornado与pika结合实例

优化业务代码逻辑

代码逻辑方便的优化,如下:

  • 减少循环
  • review 逻辑,去除冗余逻辑
  • 提取公共变量,赋值一次,减少查询数据库。

总结

经过以上的优化,我们的api 的 QPS 提升到了1200+, 由于时间问题,我们暂停了继续的优化。通过本次QPS的优化过程,有几点感悟:

  • 使用一项新技术时,一定要认真阅读官方文档,了解清楚后,再使用。
  • 不要轻易否定一项公认的“技术真理”,要拿数据说话。

个人工作总结,欢迎留言交流!


推荐阅读
  • Django框架下的对象关系映射(ORM)详解
    在Django框架中,对象关系映射(ORM)技术是解决面向对象编程与关系型数据库之间不兼容问题的关键工具。通过将数据库表结构映射到Python类,ORM使得开发者能够以面向对象的方式操作数据库,从而简化了数据访问和管理的复杂性。这种技术不仅提高了代码的可读性和可维护性,还增强了应用程序的灵活性和扩展性。 ... [详细]
  • 智能制造数据综合分析与应用解决方案
    在智能制造领域,生产数据通过先进的采集设备收集,并利用时序数据库或关系型数据库进行高效存储。这些数据经过处理后,通过可视化数据大屏呈现,为生产车间、生产控制中心以及管理层提供实时、精准的信息支持,助力不同应用场景下的决策优化和效率提升。 ... [详细]
  • 在Ubuntu系统中,由于预装了MySQL,因此无需额外安装。通过命令行登录MySQL时,可使用 `mysql -u root -p` 命令,并按提示输入密码。常见问题包括:1. 错误 1045 (28000):访问被拒绝,这通常是由于用户名或密码错误导致。为确保顺利连接,建议检查MySQL服务是否已启动,并确认用户名和密码的正确性。此外,还可以通过配置文件调整权限设置,以增强安全性。 ... [详细]
  • Python与R语言在功能和应用场景上各有优势。尽管R语言在统计分析和数据可视化方面具有更强的专业性,但Python作为一种通用编程语言,适用于更广泛的领域,包括Web开发、自动化脚本和机器学习等。对于初学者而言,Python的学习曲线更为平缓,上手更加容易。此外,Python拥有庞大的社区支持和丰富的第三方库,使其在实际应用中更具灵活性和扩展性。 ... [详细]
  • SQL Server开发技巧:修改表结构后的视图批量更新方法与实践 ... [详细]
  • PHP中元素的计量单位是什么? ... [详细]
  • 如何在Oracle ASM_Diskgroup中重命名现有磁盘
    如何在Oracle ASM_Diskgroup中重命名现有磁盘 ... [详细]
  • 深入解析 Django 中用户模型的自定义方法与技巧 ... [详细]
  • 如何运用蒙特卡洛方法计算NPV:计算机专业毕业设计遇到难题怎么办?
    许多计算机科学专业的学生在大学期间都会遇到这样的困扰:课堂上教授的内容往往偏向理论,实际应用的知识点讲解得较为浅显和概括,导致在进行毕业设计时,如运用蒙特卡洛方法计算净现值(NPV)等复杂问题时感到无从下手。本文旨在探讨如何通过深入理解和实践蒙特卡洛模拟技术,解决这类计算难题,为学生的毕业设计提供实用指导。 ... [详细]
  • 从无到有,构建个人专属的操作系统解决方案
    操作系统(OS)被誉为程序员的三大浪漫之一,常被比喻为计算机的灵魂、大脑、内核和基石,其重要性不言而喻。本文将详细介绍如何从零开始构建个人专属的操作系统解决方案,涵盖从需求分析到系统设计、开发与测试的全过程,帮助读者深入理解操作系统的本质与实现方法。 ... [详细]
  • HBase在金融大数据迁移中的应用与挑战
    随着最后一台设备的下线,标志着超过10PB的HBase数据迁移项目顺利完成。目前,新的集群已在新机房稳定运行超过两个月,监控数据显示,新集群的查询响应时间显著降低,系统稳定性大幅提升。此外,数据消费的波动也变得更加平滑,整体性能得到了显著优化。 ... [详细]
  • 从用户转型为开发者:一场思维升级的旅程 | 专访 StarRocks Committer 周威
    从用户转变为开发者,不仅是一次角色的转换,更是一场深刻的思维升级之旅。本次专访中,StarRocks Committer 周威分享了他如何在这一过程中逐步提升技术能力与思维方式,为开源社区贡献自己的力量。 ... [详细]
  • 本课程详细介绍了如何使用Python Flask框架从零开始构建鱼书应用,涵盖高级编程技巧和实战项目。通过视频教学,学员将学习到Flask的高效用法,包括数据库事务处理和书籍交易模型的实现。特别感谢AI资源网提供的课程下载支持。 ... [详细]
  • MySQL性能优化与调参指南【数据库管理】
    本文详细探讨了MySQL数据库的性能优化与参数调整技巧,旨在帮助数据库管理员和开发人员提升系统的运行效率。内容涵盖索引优化、查询优化、配置参数调整等方面,结合实际案例进行深入分析,提供实用的操作建议。此外,还介绍了常见的性能监控工具和方法,助力读者全面掌握MySQL性能优化的核心技能。 ... [详细]
  • 如何在Java中高效构建WebService
    本文介绍了如何利用XFire框架在Java中高效构建WebService。XFire是一个轻量级、高性能的Java SOAP框架,能够简化WebService的开发流程。通过结合MyEclipse集成开发环境,开发者可以更便捷地进行项目配置和代码编写,从而提高开发效率。此外,文章还详细探讨了XFire的关键特性和最佳实践,为读者提供了实用的参考。 ... [详细]
author-avatar
快乐xin_yi
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有