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

2024-05-05 03:32

本文主要是介绍我是怎么从30个并发平均每个2000毫秒 到 300个并发平均每个178毫秒的,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近一个多月一直在做服务器的性能优化,老大的要求是要做到300个并发,控制在200毫秒以内,就说说我最近做的内容吧。
从30个并发平均每个2000毫秒 到 300个并发平均每个178毫秒
简单介绍一下做了那些优化:
01、减少log日志的打印
02、减少redis的交互
03、耗时操作的处理
04、大文件信息的存储
05、python的缓存机制
06、异步处理非返回操作

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

由于之前一直定位错误,导致了很多弯路,现发现一个比较好的定位方法 --- 逐个函数定位
需要借用压测工具:wrk 或 jmeter

测试性能顺序:纯服务器性能 -- 加上参数处理时的性能 -- 加上第一个函数时的性能 -- 加上第二个函数时的性能 等等
如果在添加某一个步骤时性能变差很多,说明里有问题,需要仔细排查
简单放两个对比图

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

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

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

二、性能处理

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一样,简单易懂

方法三:redis + cacheout

(主要考虑到负载均衡,可能会有多个服务,但会公用一个redis)
按理说现在已经完全达到了要求,对音频(根据url下载的)的处理已经最优化了,但有一个问题是音频文件还一直存在于服务器内,增加内存,那就想办法移除。
于是就有了这个redis + cacheout的想法。
存储:
URL下载音频 -- 读取音频 -- 将音频信息存至redis 和 缓存中 -- 删除音频文件
读取:
获取音频名称 -- 缓存查找 -- redis查找 -- URL下载存储

06、异步处理非返回操作
一次请求处理中,打印log和发送日志,以及一些I/O是避免不了的,所以我们会用到子线程异步存储,让这些耗时的去一边处理,不影响主线的处理。
另加一个小点-如果你的用户请求是有顺序的,那么在存储redis时也可以用一下时间差,但一定要把握好!
我这里用的是twisted的threads

threads.deferToThread(save_user_info, "voice_body", voice, 1)

附送:使同步阻塞函数秒表非阻塞异步并发函数--twisted框架
一、使同步函数秒变异步并发函数
如果需要返回值, 如run2()函数
给请求函数添加装饰器@inlineCallbacks
并使用yield进行接收返回值

@inlineCallbacks
def run2():"""主函数"""# 将耗时函数放入另一个线程执行,返回一个deferred对象d = yield (threads.deferToThread(largeFibonnaciNumber))# 等待返回的结果 再做处理print(d)

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

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

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

Git代码: 公众号后台回复 python_sanic

这篇关于我是怎么从30个并发平均每个2000毫秒 到 300个并发平均每个178毫秒的的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/960725

相关文章

Java JUC并发集合详解之线程安全容器完全攻略

《JavaJUC并发集合详解之线程安全容器完全攻略》Java通过java.util.concurrent(JUC)包提供了一整套线程安全的并发容器,它们不仅是简单的同步包装,更是基于精妙并发算法构建... 目录一、为什么需要JUC并发集合?二、核心并发集合分类与详解三、选型指南:如何选择合适的并发容器?在多

Java 结构化并发Structured Concurrency实践举例

《Java结构化并发StructuredConcurrency实践举例》Java21结构化并发通过作用域和任务句柄统一管理并发生命周期,解决线程泄漏与任务追踪问题,提升代码安全性和可观测性,其核心... 目录一、结构化并发的核心概念与设计目标二、结构化并发的核心组件(一)作用域(Scopes)(二)任务句柄

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

Spring Security 前后端分离场景下的会话并发管理

《SpringSecurity前后端分离场景下的会话并发管理》本文介绍了在前后端分离架构下实现SpringSecurity会话并发管理的问题,传统Web开发中只需简单配置sessionManage... 目录背景分析传统 web 开发中的 sessionManagement 入口ConcurrentSess

MySQL中处理数据的并发一致性的实现示例

《MySQL中处理数据的并发一致性的实现示例》在MySQL中处理数据的并发一致性是确保多个用户或应用程序同时访问和修改数据库时,不会导致数据冲突、数据丢失或数据不一致,MySQL通过事务和锁机制来管理... 目录一、事务(Transactions)1. 事务控制语句二、锁(Locks)1. 锁类型2. 锁粒

深入解析Java NIO在高并发场景下的性能优化实践指南

《深入解析JavaNIO在高并发场景下的性能优化实践指南》随着互联网业务不断演进,对高并发、低延时网络服务的需求日益增长,本文将深入解析JavaNIO在高并发场景下的性能优化方法,希望对大家有所帮助... 目录简介一、技术背景与应用场景二、核心原理深入分析2.1 Selector多路复用2.2 Buffer

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

java如何实现高并发场景下三级缓存的数据一致性

《java如何实现高并发场景下三级缓存的数据一致性》这篇文章主要为大家详细介绍了java如何实现高并发场景下三级缓存的数据一致性,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 下面代码是一个使用Java和Redisson实现的三级缓存服务,主要功能包括:1.缓存结构:本地缓存:使

怎么用idea创建一个SpringBoot项目

《怎么用idea创建一个SpringBoot项目》本文介绍了在IDEA中创建SpringBoot项目的步骤,包括环境准备(JDK1.8+、Maven3.2.5+)、使用SpringInitializr... 目录如何在idea中创建一个SpringBoot项目环境准备1.1打开IDEA,点击New新建一个项