我是怎么一步步用go找出压测性能瓶颈
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~
序言:
笔者要在线上服务器load日志并且重放来测一些机器性能指标。模拟机器资源比较少,相对的被模拟的线上机器日志量大,假设线上单机qps有1w,那么5台机器组成的集群5w个qps。模拟机器压测客户端需要比5w个qps更快,才有比较意义。
第一章:HTTP初体验
正所谓“人生苦短,我用python”,python自带了urllib2、urllib3以及第三方的request。支持的代理访问、添加请求头基本满足功能需求。笔者用urllib2+multiprocessing库顺利了码完代码运行之,查看qps只有2k多,这显然远远低于需求。在加大进程数到cpu核数的数倍之多,也发现python仅能达到3k多。事出必有因,于是笔者便通过监控界面和shell小工具来找机器各种茬。
第二章:“中世纪黑暗期”
中世纪是黑暗漫长的时期,你做了很多事情,但却输出很少,留下来的是尝试后的经验总结。从cpu、内存、硬盘、网络各方面数据看。cpu使用率90%多,内存用满、硬盘wa很低、网络千兆网卡满载。最首先的是把千兆网卡机器替换成万兆网卡机器。查看timewait的连接数达到1w3多。那就先优化下看起来是"瓶颈"的东西。配置tcp_timestamps=1, tcp_tw_reuse=1, tpc_tw_recycle=1。sysctl -p生效下最新的配置,timewait连接数没下去,并发数没上来。既然硬件该做的设置都完了,那为什么别人家的露娜那么秀,我家的就是一坨屎呢。
再回过头来考虑程序架构问题。反省自己,首先urllib2、request库是网络io阻塞的,其次网络是短连接的,再次这么多进程切换系统开销也很大。在广袤的互联网海洋中遨游了一番,得出的结论就是grequest库可能是个解决办法。gevent是个协程库,它使用greenlet库提供的基于libev实现的高性能异步网络框架。Perfect!看起来是那么的完美。于是又尝试重写了程序。可是性能还是没有上去。那到底是不是python语言自身的限制问题,导致cpu高居不下,并发量又上不去呢?这里留个疑问,到文章的最后再来回答这个问题。
第三章:豁朗开朗
不甘心并且不再纠结于python,用当下网红golang重写下。golang的协程库号称是性能优秀,语言层面支持并行的,易于书写的利器。写完跑一跑,并发量还是上不去。一直保持打死都不放弃的精神,笔者再次用go的第二性能利器自带的golang pprof分析下代码的瓶颈。pprof生成的报告还可以用uber第三方组件go-torch生成更直观的火焰图。如图1所示。从火焰图查看出runtime.gcBgMarkWorker(gc:垃圾回收器),并且runtime.mallocgc也占用大量cpu时间。接着进行内存占用分析,使用go tool pprof -alloc_space replay1 /tmp/mem.prof查看如图2 所示,敲入top10命令,发现pull_worker累加分配了600多G内存,占比93%,list pull_worker命令找到该函数的瓶颈点。这个r4变量的初始化放在一个for循环内,r4是用于临时读取响应body,这个r4每次请求都重复分配,导致内存居高不下,解决办法是把他放在for循环外。
终章:总结
好了,至此单机并发量最高可以到3w了,也差不多达到计划的目标了。用两台这种机器组成的肉鸡就可以满足5w qps的请求了。再来回答之前留下来的问题,python语言并发上不去只是因为,库不支持从外面提供读buffer读取响应body,导致内存暴增,这不是语言本身的问题。相信python并没有那么差。同时,也熟悉了一门新利器go语言。go的原生协程支持和性能分析利器还是非常直观非常好用的,力荐!!
图1:性能瓶颈前的cpu火焰图
图2:找到内存使用最多的函数
找到增长最多的代码
问答
相关阅读
此文已由作者授权腾讯云+社区发布,原文链接:https://cloud.tencent.com/developer/article/1160803?fromSource=waitui
欢迎大家前往腾讯云+社区或关注云加社区微信公众号(QcloudCommunity),第一时间获取更多海量技术实践干货哦~
海量技术实践经验,尽在云加社区!
我是怎么一步步用go找出压测性能瓶颈的更多相关文章
- 记录一下通过分析Tomcat内部jar包找出request.getReader()所用的字符编码在哪里设置和起效的完整分析流程
前言: 之前写Java服务端处理POST请求时遇到了请求体转换成字符流所用编码来源的疑惑,在doPost方法里通过request.getReader()获取的BufferedReader对象内部的 R ...
- 我是如何一步步裹挟老板从.net 转到 java 阵营的
我是如何一步步裹挟老板从.net 转到 java 阵营的 仅记录从 .net(C#) 转到 java 的一些心路历程 时间点跨度 2016 — 2017 一.前 xx 公司同事群的一次聊天 前公司同事 ...
- SQL注入—我是如何一步步攻破一家互联网公司的
最近在研究Web安全相关的知识,特别是SQL注入类的相关知识.接触了一些与SQL注入相关的工具.周末在家闲着无聊,想把平时学的东东结合起来攻击一下身边某个小伙伴去的公司,看看能不能得逞.不试不知道,一 ...
- Windbg找出死锁
使用Windbg找出死锁,解决生产环境中运行的软件不响应请求的问题 前言 本文介绍本人的一次使用Windbg分析dump文件找出死锁的过程,并重点介绍如何确定线程所等待的锁及判断是否出现了死锁. 对于 ...
- 使用Windbg找出死锁,解决生产环境中运行的软件不响应请求的问题
前言 本文介绍本人的一次使用Windbg分析dump文件找出死锁的过程,并重点介绍如何确定线程所等待的锁及判断是否出现了死锁. 对于如何安装及设置Windbg请参考:<使用Windbg和SoS扩 ...
- 我是如何一步步编码完成万仓网ERP系统的(四)登录的具体实现
https://www.cnblogs.com/smh188/p/11533668.html(我是如何一步步编码完成万仓网ERP系统的(一)系统架构) https://www.cnblogs.com/ ...
- 我是如何一步步编码完成万仓网ERP系统的(十二)库存 1.概述
https://www.cnblogs.com/smh188/p/11533668.html(我是如何一步步编码完成万仓网ERP系统的(一)系统架构) https://www.cnblogs.com/ ...
- 我是如何一步步编码完成万仓网ERP系统的(十三)库存 2.加权平均价
https://www.cnblogs.com/smh188/p/11533668.html(我是如何一步步编码完成万仓网ERP系统的(一)系统架构) https://www.cnblogs.com/ ...
- 我是如何一步步编码完成万仓网ERP系统的(十四)库存 3.库存日志
https://www.cnblogs.com/smh188/p/11533668.html(我是如何一步步编码完成万仓网ERP系统的(一)系统架构) https://www.cnblogs.com/ ...
随机推荐
- Android开发环境包下载地址
Android SDK Android NDK Android Studio 官方下载地址 (网上转来的) 如果下载速度很慢或者无法下载,有三种解决方法 1.忍耐. 2.使用P2SP下载工具,比如 ...
- 2、ASP .NETCore 2.0之视图
一.Razor基础 声明:Razor不是编程语言,是服务器端标记语言.Razor是一种允许开发者在网页中嵌入服务器端代码的标记语法(主要是针对VB和C#). 1.C#中Razor基本语法 (1).Ra ...
- numpy 数组运算
数组的减法:不同维数
- spring-第二章-AOP
一,回顾 1.控制反转(IOC) 以前创建对象,由我们自己决定,现在我们把管理对象的声明周期权力交给spring; 2.依赖注入(DI) A对象需要B对象的支持,spring就把B注入给A,那么A就拥 ...
- OCP换题库了,052新加的考题及答案整理-第16题
16.Your database Is configured In archivelog mode. The USERS01 tablespace Is currently online. You a ...
- TCP/IP学习笔记(3)-IP、ARP、RARP协议
这三个协议放到一起学习是因为这三个协议处于同一层,ARP协议用来找到目标主机的Ethernet网卡Mac地址,IP则承载要发送的消息.数据链路层可以从ARP得到数据的传送信息,而从IP得到要传输的数据 ...
- jquery源码解析:jQuery静态属性对象support详解
jQuery.support是用功能检测的方法来检测浏览器是否支持某些功能.针对jQuery内部使用. 我们先来看一些源码: jQuery.support = (function( support ) ...
- [Swift实际操作]八、实用进阶-(6)通过属性进行对象间的消息传递
本文将演示,如何通过一个对象作为另一个对象的属性,从而通过设置属性的值,来实现对象之间的消息传递.首先打开自定义视图的代码文件(CustomView.swift) import UIKit //使当前 ...
- PyQt5(3)——信号和槽初探
信号和槽是QT的核心机制(当信号发射时,链接的槽函数会自动执行) 在pyqt5中信号和槽通过 QObject.signal.connect()链接. QObject类或子类(QWidget)派生的类都 ...
- CH5102 Mobile Service
CH5102 Mobile Service 描述 一个公司有三个移动服务员,最初分别在位置1,2,3处.如果某个位置(用一个整数表示)有一个请求,那么公司必须指派某名员工赶到那个地方去.某一时刻只有一 ...