前言

这篇文章的主题是记录一次 Python 程序的性能优化,在优化的过程中遇到的问题,以及如何去解决的。为大家提供一个优化的思路,首先要声明的一点是,我的方式不是唯一的,大家在性能优化之路上遇到的问题都绝对不止一个解决方案。

如何优化

首先大家要明确的一点是,脱离需求谈优化都是耍流氓,所以有谁跟你说在xx机器上实现了百万并发,基本上可以认为是不懂装懂了,单纯的并发数完全是无意义的。其次,我们优化之前必须要有一个目标,需要优化到什么程度,没有明确目标的优化是不可控的。再然后,我们必须明确的找出性能瓶颈在哪里,而不能漫无目的的一通乱搞。

需求描述

这个项目是我在上家公司负责一个单独的模块,本来是集成在主站代码中的,后来因为并发太大,为了防止出现问题后拖累主站服务,所有由我一个人负责拆分出来。对这个模块的拆分要求是,压力测试 QPS 不能低于3万,数据库负载不能超过50%,服务器负载不能超过70%,单次请求时长不能超过70ms,错误率不能超过5%。

环境的配置如下:

服务器:4核8G内存,CentOS7系统,SSD 硬盘
数据库:MySQL 5.7,最大连接数 800
缓存: Redis,1G 容量。

以上环境都是购买自腾讯云的服务。

压测工具:locust,使用腾讯的弹性伸缩实现分布式的压测。

需求描述如下:

用户进入首页,从数据库中查询是否有合适的弹窗配置,如果没有,则继续等待下一次请求、如果有合适的配置,则返回给前端。这里开始则有多个条件分支,如果用户点击了弹窗,则记录用户点击,并且在配置的时间内不再返回配置,如果用户未点击,则24小时后继续返回本次配置,如果用户点击了,但是后续没有配置了,则接着等待下一次。

重点分析

根据需求,我们知道了有几个重要的点,1、需要找出合适用户的弹窗配置,2、需要记录用户下一次返回配置的时间并记录到数据库中,3、需要记录用户对返回的配置执行了什么操作并记录到数据库中。

调优

我们可以看到,上述三个重点都存在数据库的操作,不只有读库,还有写库操作。从这里我们可以看到如果不加缓存的话,所有的请求都压到数据库,势必会占满全部连接数,出现拒绝访问的错误,同时因为 SQL 执行过慢,导致请求无法及时返回。所以,我们首先要做的就是讲写库操作剥离开来,提升每一次请求响应速度,优化数据库连接。整个系统的架构图如下:

将写库操作放到一个先进先出的消息队列中来做,为了减少复杂度,使用了Redis 的 list 来做这个消息队列。

然后进行压测,结果如下:

QPS 在 6000 左右 502 错误大幅上升至 30%,服务器 CPU 在 60%-70% 之间来回跳动,数据库连接数被占满 TCP 连接数为 6000 左右,很明显,问题还是出在数据库,经过排查 SQL 语句,查询到原因就是找出合适用户的配置操作时每次请求都要读取数据库所导致的连接数被用完。因为我们的连接数只有 800,一旦请求过多,势必会导致数据库瓶颈。好了,问题找到了,我们继续优化,更新的架构如下:

我们将全部的配置都加载到缓存中,只有在缓存中没有配置的时候才会去读取数据库。

接下来我们再次压测,结果如下:

QPS 压到 2万左右的时候就上不去了,服务器 CPU 在 60%-80% 之间跳动,数据库连接数为300个左右,每秒TPC连接数为1.5万左右。

这个问题是困扰我比较久的一个问题,因为我们可以看到,我们2万的 QPS,但是TCP 连接数却并没有达到2万,我猜测,TCP连接数就是引发瓶颈的问题,但是因为什么原因所引发的暂时无法找出来。

这个时候猜测,既然是无法建立 TCP 连接,是否有可能是服务器限制了 socket 连接数,验证猜测,我们看一下,在终端输入 ulimit -n 命令,显示的结果为65535,看到这里,觉得 socket 连接数并不是限制我们的原因,为了验证猜测,将 socket 连接数调大为100001.

再次进行压测,结果如下:

QPS压到2.2万左右的时候就上不去了,服务器cpu在60%-80%之间跳动,数据库连接数为300个左右,每秒 TCP 连接数为1.7万左右。

虽然有一点提升,但是并没有实质性的变化,接下来的几天时间,我发现都无法找到优化的方案,那几天确实很难受,找不出来优化的方案,过了几天,再次将问题梳理了一遍,发现,虽然socket连接数足够,但是并没有全部被用上,猜测,每次请求过后,tcp连接并没有立即被释放,导致socket无法重用。经过查找资料,找到了问题所在,

TCP 链接在经过四次握手结束连接后并不会立即释放,而是处于 timewait 状态,会等待一段时间,以防止客户端后续的数据未被接收。

好了,问题找到了,我们要接着优化,首先想到的就是调整 TCP 链接结束后等待时间,但是 Linux 并没有提供这一内核参数的调整,如果要改,必须要自己重新编译内核,幸好还有另一个参数 net.ipv4.tcp_max_tw_buckets, timewait 的数量,默认是180000。我们调整为 6000,然后打开 timewait 快速回收,和开启重用,完整的参数优化如下:

#timewait 的数量,默认是 180000。
net.ipv4.tcp_max_tw_buckets = 6000net.ipv4.ip_local_port_range = 1024 65000#启用 timewait 快速回收。
net.ipv4.tcp_tw_recycle = 1#开启重用。允许将 TIME-WAIT sockets 重新用于新的 TCP 连接。
net.ipv4.tcp_tw_reuse = 1

我们再次压测,结果显示:QPS 5万,服务器 CPU 70%,数据库连接正常,TCP 连接正常,响应时间平均为 60ms,错误率为 0%。

结语

到此为止,整个服务的开发、调优、和压测就结束了。回顾这一次调优,得到了很多经验,最重要的是,深刻理解了web开发不是一个独立的个体,而是网络、数据库、编程语言、操作系统等多门学科结合的工程实践,这就要求web开发人员有牢固的基础知识,否则出现了问题还不知道怎么分析查找。

ps:服务端开启了 tcp_tw_recycle 和 tcp_tw_reuse是会导致一些问题的,我们为了优化选择牺牲了一部分,获得另一部分,这也是我们要明确的,具体的问题可以查看耗子叔的文章TCP 的那些事儿(上)

来源:https://segmentfault.com/a/1190000018075241

记一次单机系统的性能优化:最后竟是 TCP 的锅相关推荐

  1. 系统架构性能优化思路

    -     前言    - 今天谈下业务系统性能问题分析诊断和性能优化方面的内容.这篇文章重点还是谈已经上线的业务系统后续出现性能问题后的问题诊断和优化重点. 系统性能问题分析流程 我们首先来分析下如 ...

  2. ERP服务器性能改善,ERP系统的性能优化及其实现

    摘要: ERP(Enterprise Resource Planning)系统作为现代企业中最重要的管理信息系统之一,集合企业内部的所有资源,进行有效的计划与控制,使企业的经营模式达到最大效益,具有复 ...

  3. 以字节跳动内部 Data Catalog 架构升级为例聊业务系统的性能优化

    背景 字节跳动 Data Catalog 产品早期,是基于 LinkedIn Wherehows 进行二次改造,产品早期只支持 Hive 一种数据源.后续为了支持业务发展,做了很多修修补补的工作,系统 ...

  4. 网维大师系统虚拟盘控制台 网络中存在另外一台主服务器,网维大师系统虚拟盘性能优化及常见问题...

    网维大师系统虚拟盘性能优化及常见问题 性能优化及常见问题: ├─为什么客户机无法获取dhcp? ├─如何对网卡进行pnp? ├─如何对主板.显卡.声卡进行pnp? ├─客户机系统的页面文件(虚拟内存) ...

  5. matlab 动态优化,基于Matlab的测控系统动态性能优化与仿真

    随着测试技术的发展,人们采用传感器测控系统的动态性能指标来表征系统性能.描述传感器的主要动态性能指标是工作频带,系统的动态性能研究的重要一步是在辨识出合适的模型结构和模型参数的基础上,根据现有的工作频 ...

  6. 亿级数据量系统数据库性能优化方案

    一.数据库性能瓶颈主要原因 1.数据库连接 MySQL数据库默认连接为100,我们可以通过配置initialSize.minIdle.maxActive等进行调优,但由于硬件资源的限制,数据库连接不可 ...

  7. linux nginx cpu 高,Linux 系统 Nginx性能优化CPU参数

    Nginx性能优化CPU参数worker_cpu_affinity使用说明 官方说明: worker_cpu_affinity Syntax:worker_cpu_affinity cpumask [ ...

  8. 面对 10 亿数据量的挑战,如何对系统进行性能优化?

    作者 | 中华石杉 责编 | 伍杏玲 本文经授权转载自石杉的架构笔记 这篇文章,我们来聊一聊在十亿级的大数据量技术挑战下,世界上最优秀的大数据系统之一的Hadoop是如何将系统性能提升数十倍的? 首先 ...

  9. 高时空损耗的Scanner会卡爆程序(记洛谷P1567的Java性能优化,Java语言描述)

    写在前面 对性能调优,其实我一个弱鸡,用的也不多,特别是这种OJ连JVM调优都不成. 大佬s勿喷,且看小菜鸡如何在一道OJ题里与Java性能搏斗! 题目要求 P1567题目链接 简单分析 10^9,没 ...

最新文章

  1. 他是第一个到达学校的人英语_日本留学:不需要英语成绩的大学盘点·私立学部篇(第三弹)...
  2. 轻松掌握移动端web开发【尺寸适配】常用解决方案
  3. python1000个常用代码-比较了1000多个Python开源项目,精选出这34个
  4. win7系统自带截图工具快捷键是什么?怎么设置快捷键
  5. 【机器学习】机器学习神器Scikit-Learn保姆级入门教程
  6. 心胸狭窄小肚鸡肠的男人_为心胸开阔的教育者编写新的剧本
  7. SpringMVC框架----RequestMapping注解
  8. [译]R语言——Shiny框架之入门(三):如何启动一个Shiny应用
  9. 《Puppet实战手册》——1.4 利用Git管理配置清单
  10. c语言删除元素1116,C语言网蓝桥杯1116 IP判断
  11. HTTP协议—状态码(思维导图速查)
  12. [CTO札记]研究:日本Rakuten(乐天)
  13. matlab 四叉树表达,已知二值图像,如题图8.4所示。 (1)对该图像使用四叉树进行划分; (2)用四叉树表达该图像。 - 试题答案网问答...
  14. 电容触摸按键实验(STM32F407)
  15. python单位根检验平稳性怎么看是否平稳_PYthon ADF 单位根检验 如何查看结果
  16. 新型冠状病毒SIR预测模型,MATLAB代码
  17. LIN总线增强型校验_相比于LIN通讯,大家可能对CAN更感兴趣
  18. 2012 Tokyo Regional C. One-Dimensional Cellular Automaton 矩阵快速幂
  19. /bin/bash^M: 坏的解释器: 没有那个文件或目录
  20. SQL2022-8-10

热门文章

  1. android webview mailto,Webview email link (mailto)
  2. 青少年python编程课_青少年之Python编程课程安排第一季
  3. ASP.NET MVC – 样式和布局简介
  4. 关于java中的字符流的一个使用例子
  5. HDU3791(二叉搜索树)
  6. 四川大学计算机学院男女生比例,川大、电子科大新生男女比例大PK 比例更佳的是……...
  7. java 二进制 定义_Java如何定义二进制格式的整数常量?
  8. 提取某一个镇的行政边界_池店镇消防安全违法典型案例通报(一)
  9. win7 php mysql扩展名_Win7 iis php mysql 开发环境配置(详细)
  10. vue垂直布局_前端页面布局中水平、垂直居中问题