Python_服務端效能高併發測試
背景
公司業務處於上升期,但是服務端卻 low 的像個 demo,於是乎重構服務端開始了;
關於測試,測試這個行業在大多數網際網路公司比較失敗,做測試的應該都有這種感覺。但是我感覺我很幸運,因為 CTO 很重視測試,他的口頭禪就是不可測試的程式都是不可靠的,所以我們公司的所有程式都會有配套的測試工具。這篇文章中的工具就是專門測試服務端而模擬的客戶端 TSP。
業務需求
重構服務端,達到接入百萬客戶端級別
實現原理
- 服務端監聽 3 個埠,這三個埠全部是裝置發起
- tsp 模擬客戶端連線服務端邏輯,從而達到裝置、使用者上線
- 採用程序池巢狀執行緒池方式,達到高併發的目的
- 程式碼中統計發包時間平均值、收包時間平均值、收包位元組大小平均值、收包錯誤率;
- 服務端採集硬體配置、cpu 負載、記憶體負載、磁碟 io 等等
具體實現
1.構建主流程,完成基於 socket 請求的收發包
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
from socket import socket,AF_INET,SOCK_STREAM
import struct
from log import log
log=log()
class socket_main:
def __init__(self,who,conn_data):
self.conn_data = conn_data
self.who = who
self.__conn(conn_data)
def __conn(self,addr):
try:
log.debug('{} _conn data:{}'.format(self.who,addr))
self.tcpCliSock = socket(AF_INET, SOCK_STREAM)
self.tcpCliSock.connect(addr)
self.tcpCliSock.setblocking(1)
self.tcpCliSock.settimeout(1)
# self.tcpCliSock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,8192)
log.debug('{} socket data:{}'.format(self.who,'success'))
except BaseException as msg:
log.error('{} socket conn_result:{}'.format(self.who,msg))
def send(self,data):
try:
try:
result = self.tcpCliSock.send(data)
except BaseException as msg:
# self.__conn(self.conn_data)
# result = self.tcpCliSock.send(data)
log.error(msg)
raise msg
log.debug('{} socket send_len:{}'.format(self.who, result))
return result
except BaseException as msg:
raise log.error('{} socket send_error:{}'.format(self.who,msg))
def recv(self,size,code):
result =''
try:
try:
result = self.tcpCliSock.recv(int(size))
while len(result)<int(size):
result +=self.tcpCliSock.recv(int(size)-len(result))
except:
pass
if not result:
log.error('{} socket recv_result ERROR:result is null'.format(self.who))
log.debug('{} socket recv_result:{}'.format(self.who, len(result)))
data_struct = struct.unpack(code, result)
log.debug('{} socket recv_result_unpack:{}'.format(self.who, data_struct))
return data_struct
except BaseException as msg:
log.error('{} socket recv_error:{}'.format(self.who,msg))
raise msg
def only_recv(self,size):
try:
result = self.tcpCliSock.recv(int(size))
while len(result) < int(size):
result += self.tcpCliSock.recv(int(size) - len(result))
log.debug('{} socket only_recv_result_len:{}'.format(self.who, len(result)))
log.debug('only_recv:{}'.format(result))
return result
except BaseException as msg:
log.error('{} socket recv_error:{}'.format(self.who,msg))
raise msg
def close(self):
try:
log.debug('{} socket has been closed'.format(self.who))
self.tcpCliSock.close()
except BaseException as msg:
log.debug('{} socket close_error:{}'.format(self.who,msg))
- 建立程序池、執行緒池套餐
def main():
print '業務程式碼'
class MyThread(threading.Thread):
def __init__(self, func, args, name=''):
threading.Thread.__init__(self)
self.name = name
self.func = func
self.args = args
def run(self):
apply(self.func, self.args)
def main_thread():
global sn
threads = []
nloops = xrange(thread_num)# thread_num併發執行緒數
for i in nloops:
mac, mac_real, sn = getMacSn()
t = MyThread(main, (mac,mac_real,sn))
threads.append(t)
for i in nloops:
threads[i].start()
for i in nloops:
threads[i].join()
if __name__=='__main__':
result = ''
pool = multiprocessing.Pool(processes=proc)# processes程序池數量
log.info("main process(%d) running..." % os.getpid())
for i in xrange(proc_num):# proc_num 併發程序數量
result = pool.apply_async(main_thread)
pool.close()
pool.join()
if not result.successful():
log.error('主程序異常:{}'.format(result.successful()))
else:
log.info('goodbye:主程序({})執行完畢'.format(os.getpid()))
- 透過在業務程式碼中計算統計引數,然後放在記憶體中累計計算,輸出到指定級別日誌中,用到的主要方法是透過設定全域性變數進行統一計算:
class globalMap:
# 拼裝成字典構造全域性變數 借鑑map 包含變數的增刪改查
map = {}
def set_map(self, key, value):
if(isinstance(value,dict)):
value = json.dumps(value)
self.map[key] = value
log.debug(key + ":" + str(value))
def set(self, **keys):
try:
for key_, value_ in keys.items():
self.map[key_] = str(value_)
log.debug(key_+":"+str(value_))
except BaseException as msg:
log.error(msg)
raise msg
def del_map(self, key):
try:
del self.map[key]
return self.map
except KeyError:
log.error("key:'" + str(key) + "' 不存在")
def get(self,*args):
try:
dic = {}
for key in args:
if len(args)==1:
dic = self.map[key]
log.debug(key+":"+str(dic))
elif len(args)==1 and args[0]=='all':
dic = self.map
else:
dic[key]=self.map[key]
return dic
except KeyError:
log.warning("key:'" + str(key) + "' 不存在")
return 'Null_'
總結
多程序的方式和多執行緒進行對比,雖然 Python 全域性鎖的限制導致執行緒有點瑕疵,但是跟程序比起併發,還是能甩程序幾條街的。透過這種方式進行高密度業務邏輯操作,可以很輕鬆找到服務端瓶頸。
宣告:看到過的好文章,轉載分享,若有侵權,請及時聯絡,速刪。
相關文章
- Jmeter效能測試:高併發分散式效能測試JMeter分散式
- 如何使用jMeter對某個OData服務進行高併發效能測試JMeter
- 遊戲服務端的高併發和高可用遊戲服務端
- 效能測試-服務端瓶頸分析思路服務端
- jmeter介面效能測試-高併發分散式部署JMeter分散式
- 主流 go-web 服務端框架效能測試GoWeb服務端框架
- 服務端效能測試你應該知道的服務端
- YApi 服務端測試新增 globalCookie ,相容自動化觸發服務端測試功能API服務端Cookie
- 從服務端視角看高併發難題服務端
- 服務端測試開發必備技能:Mock測試服務端Mock
- 【廈門】招聘golang後端開發工程師(高併發高效能後臺服務框架)Golang後端工程師框架
- netty建立聊天室服務端及單機併發測試結果Netty服務端
- Java高併發測試框架JCStressJava框架
- [服務端] 效能測試入門指南 (慎入: 6000 字長文)服務端
- 整車電效能裝置開發及測試服務
- 服務端測試是什麼?怎麼測?服務端
- 個人筆記-服務端高併發分散式架構演進之路筆記服務端分散式架構
- 介面效能測試 —— Jmeter併發與持續性壓測JMeter
- 一場為企業服務開發的效能測試報告測試報告
- 使用jMeter構造大量併發HTTP請求進行微服務效能測試JMeterHTTP微服務
- 微服務測試之效能測試微服務
- 高併發服務的幾條優化經驗優化
- 基於 Python 自建分散式高併發 RPC 服務Python分散式RPC
- Netty服務端開發及效能最佳化Netty服務端
- 挑戰 - 微服務架構下的服務端測試微服務架構服務端
- 效能測試中如何確定TPS和併發數
- 使用 jMeter 對 SAP Spartacus 進行併發效能測試JMeter
- [20190213]測試服務端開啟那些埠.txt服務端
- 我有個想法使用 locust 作為壓測核心, 寫一個服務端效能測試平臺,服務端
- HMI測試服務
- 效能測試中如何確定併發使用者數
- 服務端測試很牛逼?不要慫,幹它服務端
- 【高併發】高併發環境下如何優化Tomcat效能?看完我懂了!優化Tomcat
- 服務端c100k連線測試和客戶端65535測試驗證2服務端客戶端
- RabbitMQ/高併發面試題MQ面試題
- 測試開發之效能篇-效能測試設計
- Tomcat 高併發之道與效能調優Tomcat
- 貨拉拉服務端質量保障之測試策略篇服務端