前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我是怎么从30个并发平均每个2000毫秒 到 300个并发平均每个178毫秒的

我是怎么从30个并发平均每个2000毫秒 到 300个并发平均每个178毫秒的

作者头像
Python疯子
发布2019-01-03 10:24:45
1.4K0
发布2019-01-03 10:24:45
举报
文章被收录于专栏:Python疯子Python疯子

最近一个多月一直在做服务器的性能优化,老大的要求是要做到300个并发,控制在200毫秒以内,就说说我最近做的内容吧。

从30个并发平均每个2000毫秒 到 300个并发平均每个178毫秒

简单介绍一下做了那些优化:

01、减少log日志的打印

02、减少redis的交互

03、耗时操作的处理

04、大文件信息的存储

05、python的缓存机制

06、异步处理非返回操作

一、定位耗时操作 -- 唯一变量法

由于之前一直定位错误,导致了很多弯路,现发现一个比较好的定位方法 --- 逐个函数定位

需要借用压测工具:wrk 或 jmeter

测试性能顺序:纯服务器性能 -- 加上参数处理时的性能 -- 加上第一个函数时的性能 -- 加上第二个函数时的性能 等等

如果在添加某一个步骤时性能变差很多,说明里有问题,需要仔细排查

简单放两个对比图

纯服务器性能 + 参数处理时的性能

+参数处理时.png

纯服务器性能 + 参数处理时的性能 + 读取音频

+读取音频

我们发现两个性能测试只差一个读取音频函数 但形成却相差很多,说明在读取音频这里是一个巨大的耗时,那么就要想办法处理掉

二、性能处理

01、我们可能会感觉打印一个log不会是耗时操作,但通过唯一变量法发现 打印log也是耗时的,因为要控制在200ms以内,那就是任何耗时的都要深思熟虑,于是减少log的打印

02、当对redis做读取操作时,每次读取都要花费几毫秒,那就想办法优化甚至怎么减少redis的读取:

优化:

a、当能确认并必确认这是第一个存储并不需要获取时,就可以减少一次获取,直接存储。

b、要使用redis的缓存池

c、使用redis的通道法

减少判断:

先假想代码处理流程,中间用到了几次redis的读取,然后通过redis的INFO commandstats 命令,定位redis的耗时,以及有没有多余的操作

redis的耗时

数据信息为:操作次数 – 总耗时 – 平均耗时

这样我们就能清清楚楚的看到用到了几次读写操作,分别耗时多少

具体详见:

redis的使用,以及耗时定位

03+04+05、耗时操作的处理

一般指:mysql的读取 -- I/O操作

当频繁性的使用一个数据时就要想着做缓存处理,缓存也会考虑处理时间,个人感觉处理时间(如有不对,请斧正):

本地磁盘 > redis > 内存 > 机制化内存

通过”定位耗时操作 -- 唯一变量法“ 得知,音频文件的读取是一个很耗时的操作,那么就做缓存处理。

方法一:redis缓存

说到缓存数据,首先想到了内存性数据库redis,于是想办法将音频存至redis中,操作很简单,以音频名称为key值 -- 读取的信息为value进行存储(注意类型为bytes类型) + 过期时间(redis的存储大小为512M)

很快代码写完了,那就测测效果吧,一次效果还不错,提升了不少,但还是很耗时,而且与想象的相差很多,预想存储redis,读取都是几毫秒 最多也就10+毫秒的时间,为什么测试结果与预想结果查那么多,在redis读取那里加上时间,测一下读取时间,一看打印时间都在80+以上有的甚至到达150+,后来发现原因:数据过大,读取缓慢

方法二:cacheout缓存

于是将音频的数据存至内存中,发小效果不错,几乎不耗时,达到了理想状态。

转念一想,数据会一直累加与服务器内存,导致整个服务器增加,于是查找有效的缓存机制,就找到了cacheout缓存

它可以设置同时设置多个缓存,并且可以设置缓存机制(优先策略),设置有效条目数 以及 设置有效时间, 大多数操作基本和redis一样,简单易懂

代码语言:javascript
复制
    # 判断是否存在
    cache["voice_store"].has(voice_id)
    # 根据key获取
    cache["voice_store"].get(voice_id)
    # 存储
    cache["voice_store"].set(voice_store_key, voice_body)
方法三:redis + cacheout

(主要考虑到负载均衡,可能会有多个服务,但会公用一个redis)

按理说现在已经完全达到了要求,对音频(根据url下载的)的处理已经最优化了,但有一个问题是音频文件还一直存在于服务器内,增加内存,那就想办法移除。

于是就有了这个redis + cacheout的想法。

存储:

URL下载音频 -- 读取音频 -- 将音频信息存至redis 和 缓存中 -- 删除音频文件

读取:

获取音频名称 -- 缓存查找 -- redis查找 -- URL下载存储

06、异步处理非返回操作

一次请求处理中,打印log和发送日志,以及一些I/O是避免不了的,所以我们会用到子线程异步存储,让这些耗时的去一边处理,不影响主线的处理。

另加一个小点-如果你的用户请求是有顺序的,那么在存储redis时也可以用一下时间差,但一定要把握好!

我这里用的是twisted的threads

代码语言:javascript
复制
threads.deferToThread(save_user_info, "voice_body", voice, 1)

附送:使同步阻塞函数秒表非阻塞异步并发函数--twisted框架

一、使同步函数秒变异步并发函数

如果需要返回值, 如run2()函数

给请求函数添加装饰器@inlineCallbacks

并使用yield进行接收返回值

代码语言:javascript
复制
@inlineCallbacks
def run2():
    """
    主函数
    """
    # 将耗时函数放入另一个线程执行,返回一个deferred对象
     d = yield (threads.deferToThread(largeFibonnaciNumber))

     # 等待返回的结果 再做处理
     print(d)

二、如果不需要返回值可以使用addCallback回调函数 如run()函数

代码语言:javascript
复制
def run():
    """
    主函数
    """
    # 将耗时函数放入另一个线程执行,返回一个deferred对象
    d = threads.deferToThread(largeFibonnaciNumber)
    # 添加回调函数
    d.addCallback(fibonacciCallback)

具体代码见项目中的other目录

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.01.03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、定位耗时操作 -- 唯一变量法
  • 二、性能处理
    • 方法一:redis缓存
      • 方法二:cacheout缓存
        • 方法三:redis + cacheout
        相关产品与服务
        云数据库 Redis
        腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档