Flask中的后端并发思考(以Mysql:too many connections为例)

news2024/12/28 5:42:30

之前写过一篇《CentOS 下部署Nginx+Gunicorn+Supervisor部署Flask项目》,最近对该工程的功能进行了完善,基本的功能单元测试也做了。

觉得也是时候进行一下压力测试了,所以利用Jmeter对部署到服务器的项目进行了简单的压力测试。在之前的笔记中写过,这个API的资源获取,为了不对数据库造成大量的读取压力,采用了Redis进行缓存,所以大量的GET方法下的接口都很坚挺,基本没有出乱子,但是在其中一个需要Log数据到Mysql的接口出问题了,具体表示是数据库插入失败。检查服务器上的Mysql日志发现,错误内容为:

ERROR 1040: Too many connections

想起来之前一篇笔记中遇到Mysql server has gone away的问题,其中一步是需要对数据库的time_out进行设置,所以自然而然,搜索这个问题的解决方案中,最初步的自然是增大mysql对于最大连接数的上限:

show variables like 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 151   |
+-----------------+-------+
1 row in set (0.00 sec)

然后对mysql的最大连接数进行修改来尝试解决问题。具体可见参考一。可是这个方法有两个问题:

1.最大连接数设置到多少比较合适?太大Mysql会占用服务资源。

2.极端高并发情况下,只是允许更大的连接,可是Mysql的I/O瓶颈还是会造成有些服务如果等待Mysql操作完成再返回很可能很久甚至超时。

考虑到我这个接口中,是存储日志,也就是大量写入Mysql数据而且无需校检。所以我决定采用异步来解决这个问题:

1.请求过来的时候先处理请求并立即返回给客户端

2.日志写入这个功能做成异步,也就是后台操作,考虑到高并发通常不会太持久,把日志写入的压力分散到后面的时间是比较可行的一个办法。

所以找到了这个异步操作的Python库Celery, 简单来说就是把耗时的操作丢给他去处理,Flask(或者说Gunicorn)不管这个操作而在处理完成请求之后直接返回。

对于为什么Flask应用一步步加上了Redis, 加上了Gunicorn(Gevent),到现在需要Celery, 我画了几张张图来理解。

一个典型的Flask应用(自带调试WSGI):

但是这个的问题在于他是阻塞的,每次请求过来没处理完没办法处理下一个请求!所以在调试的时候,会有提示你:

WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.

所以真正用的时候我们都要吧WSGI更换成Gunicorn, 利用服务器的多进程来达到并发,也就是同时处理多个请求。事实上,在利用了协成的Gevent后,每一个gunicorn的worker还可以处理多个请求:

到这一步后的问题是每个worker都要去对mysql的资源进行处理,这就造成数据库压力大而且响应速度慢。所以我们就利用Redis来缓存常用的数据在内存中来达到加速资源访问的目的:

但是,今天的问题出来了,利用Redis达到了对资源缓存减轻数据库压力的目的,但是对Mysql的写入呢,每个worker 每个请求还是要直接写入数据库(比如我的api的Log),那么这个在高并发的时候就是个问题了。所以利用Celery,而celery本身不存储资源,他需要一个中间人来帮忙存储异步处理的数据,既然官方推荐也有Redis我自然就把redis作为中间人。也就是说Celery会以队列的形式,不断的从中间人那里拿到自己的任务并后台进行处理。

也就是说每次请求,如果还有对数据库的写入,那么我们把它延迟执行而不是等它执行完毕才返回给客户。这样子Flask就可以不断的接收新请求,而且通过对于延迟执行时间的调度,我们可以把高峰时间的写入请求压力分散到后续的时间中去。

总结起来:

1.Gunicorn和gevent保证了flask可以同时处理多个请求

2.利用Redis/Memecached 缓存可以减轻数据库的读取压力

2.但是如果请求耗时(比如大量的数据库插入,发送验证邮件等),你这个进程资源还是有被卡住的可能。

3.而利用Celery来后台处理耗时任务可以保证Flask能够较快响应而且不被阻塞,同时减轻了数据库的高峰写入压力。

注意:

1.Celery的worker和Gunicorn一样需要启动,可以与flask服务放在一起通过supervisor来管理,这样他们可以保持协同工作。

2.Windows的Celery只支持到3.1.25,所以你如果在windows上调试,请指定该版本。

3.如果你的后台任务是操作数据库,操作完成后记得释放数据库连接,例如Session.remove(Sqlalchemy scoped_session).

3.具体的操作步骤可见参考

参考:


1.https://bluemedora.com/mysql-performance-max-connections/

2.使用Jmeter进行负载测试

3.在 Flask 中使用 Celery

4.官方:Celery - Distributed Task Queue

5.supervisor 启动 celery 及启动中的问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/140689.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

10个 Python 高效编程小技巧

初识Python语言,觉得python满足了你上学时候对编程语言的所有要求。python语言的高效编程技巧让那些曾经苦逼学了四年c或者c的人,兴奋的不行不行的,终于解脱了。高级语言,如果做不到这样,还扯啥高级呢? 01…

【密码学】HMAC与HS256算法

哈希算法加盐 传统的哈希算法: digest hash(input)因为相同的输入会产生相同的输出,所以想要加盐,加盐的目的就在于,使输入有所变化: digest hash(salt input)这个salt可以看作是一个额外的“认证码”&#xff0…

ChatGPT 使用 API 进行 Postman 调用测试

当获得 ChatGPT 的 API Key 以后,想使用 Postman 来进行一下调用。调用的方法为 POST。需要设置几个参数。我们希望使用的 EndPoint 是:API EndPoint访问使用的 EndPoint 是:https://api.openai.com/v1/completions授权方法授权的方法使用的是…

FortiGate FGCP HA 配置文档

概述 FortiOS 提供 6 种冗余解决方案,工业标准的 VRRP 和 5 种专有的解决方案: FortiGate Cluster Protocol (FGCP) high availability,FortiGate Session Life Support Protocol (FGSP) high availability,Session-Aware Load …

Spring Cloud LoadBalancer(负载均衡)

简介 了解过Spring Cloud,就知道,之前Spring Cloud中默认的负载均衡组件为ribbon,ribbon是Netflix开源的组件,但是目前已经停止更新了。所以Spring官方推出了Spring Cloud LoadBalancer。而且Spring Cloud LoadBalancer是目前唯一…

win11下通过qemu 安装win10 arm系统

安装qemu QEMU for Windows – Installers (64 bit) 我选了最新的20221230的版本,我将其安装在c:\qemu7\下,另外在环境变量中加入这个路径 然后在别的盘上建立一个路径,名称随意,不要有中文和空格即可,我放在了e:\qe…

电脑蓝屏提示错误代码0X000000B4怎么办?

电脑蓝屏可以说是Windows的一个常见问题了。蓝屏状况数不胜数,关键还得看是何终止代码。 如果电脑蓝屏,提示错误代码0X000000B4是什么意思?这是由于Windows不能启动显卡驱动,从而无法进入图形界面。 蓝屏错误0X000000B4可能由驱…

docker搭建redis集群(Cluster版三主三从)

docker搭建redis集群(Cluster版三主三从编写脚步建立配置redis的配置文件启动六个redis服务创建cluster集群测试集群的高可用编写脚步建立配置redis的配置文件 建立配置文件脚本 vim redis.shfor port in $(seq 1 6); \ do \ mkdir -p /volumn/redis/node-${port}/conf touch…

怎么修复老照片?这三个修复方法让你轻松学会

大家在翻看以前的照片时,有没有发现有一些照片的颜色泛黄,内容也变得有些模糊不清了,遇到这种情况应该怎么办呢?不知道的小伙伴也不要着急,今天我就给大家分享几个模糊老照片修复教程,教会大家如何修复老照…

一直没明白的 HTTPS,今天必须让你懂了~

大家第一次接触 HTTPS 协议的时候是不是和我一样,非常困惑。 这玩意概念又多又繁琐。尤其是里面的公钥私钥啥的。 当时就特别想知道,为什么用公钥加密却不能用公钥解密? 看完这篇文章你会弄明白,同时还会解锁很多HTTPS里的细节…

1.所有被new出来的实例都是存放在堆里的吗?Android面经

问题: 所有被new出来的实例都是存放在堆里的吗? 相关知识点: 堆和栈、标量替换、栈上分配、逃逸分析 思考: 首先,这样问了,答案肯定是不是所有new出来的实例都存放在堆里,不然下面没法继续问了…

MODBUS转PROFINET网关在冷水机项目中应用

在电镀行业中,需要频繁用到冷水机,电镀产品在焊接过程中会产生大量的热量,这些热量若不及时散除,则有可能会导致待加工的电镀产品发生大变形,本案例的目的是通过微硬创新MODBUSRTU转PROFINET网关连接冷水机和PLC&#…

安卓玩机搞机技巧综合资源-----修复基带 改串码 基带qcn 改相关参数 终结贴

有需要了解这方面常识的友友梦可以先参阅我这几个帖子 请点击跳转 基带qcn的备份与写入相关 格机 nv报错 高通联机修改IMEI等参数的相关解析 关于高通QPST平台功能和选项的一些简单说明 基带qcn的备份与写入相关 格机 nv报错 以上几个帖子可以初步了解基带 串码等参数方面…

面试官:如何用Excel进行预测分析?这操作绝了!

【面试题】一个社交APP, 它的新增用户次日留存、7日留存、30日留存分别是52%、25%、14%。请模拟出来,每天如果日新增6万用户,那么第30天,它的日活数会达到多少?请使用Excel进行分析。【分析思路】第1日(次日)留存用户数第1日新增用…

筛选用户权限子集记录

【问题】Is there a way to use the $map operator in a regular Mongo document query (or aggregate \$match which I believe is the same thing).What I’m trying to do is thus: Given an set of sets, return the document if any of the sets is a subset of a paramet…

SpringBoot+VUE前后端分离项目学习笔记 - 【12 Vue使用路由】

整体代码结构 Manage.vue HomeView.vue改名为Manage.vue,用以管理其他view页面【通过import 】 <template><el-container style"min-height: 100vh"><el-aside :width"sideWidth px" style"box-shadow: 2px 0 6px rgb(0 21 41 / 3…

年终盘点:元宇宙产业委多项成果荣登元宇宙行业影响力榜单

在经过了2021年元宇宙概念落地和普及后&#xff0c;2022年成为元宇宙相关产业井喷式发展的一年。元宇宙产业委在2022年多项成果荣登行业影响力榜单。 2021-2022元宇宙科技传播图书影响力榜发布&#xff0c;元宇宙产业委好书上榜 2022年9月&#xff0c;两办印发《关于新时代进一…

Internet Download Manager2023最新永久版下载及功能介绍

提到下载工具&#xff0c;大多数国人映入脑海的或许是迅雷。没错&#xff0c;当今随着互联网的迅猛发展&#xff0c;不少早期积累大量用户的国内外下载工具尽显疲态&#xff0c;止步不前&#xff0c;纷纷掉队&#xff0c;如网络快车、FDM、脱兔等等。一款名叫Internet Download…

Anaconda(python)安装教程以及创建新环境

文章目录一. Anaconda简介二. Anacoda安装1. Anacondad下载2. 安装方式三.通过conda创建新的环境四.conda常用命令一. Anaconda简介 Anaconda介绍&#xff1a;开源的Python发行版本。Anaconda指的是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包…

make_shared与new

假设有这么个类&#xff1a; class A {private:int b;public:A(int c):b(c) { cout << "call constructor..." << endl;}~A() { cout << "call destructor..." << endl;}int getValue() { return b;} }; 当创建指向 A 对象的智能…