1. 程式人生 > >WRK+fabric進行叢集部署和壓測

WRK+fabric進行叢集部署和壓測

一、   wrk部署

1、部署控制機

需要一臺機器安裝fabric和wrk作為控制機。

第一步:將fabric.rar解壓縮後把整個目錄上傳到控制機的/home目錄下

安裝包:

cffi-1.9.1.tar.gz
cryptography-1.6.tar.gz
ecdsa-0.13.tar.gz
enum34-1.1.6.tar.gz
Fabric-1.12.0.tar.gz
gmp-6.0.0a.tar.bz2
idna-2.1.tar.gz
install.sh
ipaddress-1.0.17.tar.gz
libffi-devel-3.0.5-3.2.el6.x86_64.rpm
openssl-1.0.2.tar.gz
paramiko-1.15.2.tar.gz
pyasn1-0.1.9.tar.gz
pycparser-2.17.tar.gz
pycrypto-2.6.1.tar.gz
Python-2.7.11.tgz
setuptools-30.2.0.tar.gz
six-1.10.0.tar.gz
zlib-1.2.3-29.el6.x86_64.rpm
zlib-devel-1.2.3-29.el6.x86_64.rpm

自動安裝指令碼install.sh

#!/bin/bash
#將python環境升級到2.7.11
rpm -ivh zlib-1.2.3-29.el6.x86_64.rpm
rpm -ivh zlib-devel-1.2.3-29.el6.x86_64.rpm
tar -xvf Python-2.7.11.tgz
cd Python-2.7.11
./configure
make all
make install
make clean
make distclean
mv /usr/bin/python /usr/bin/python_old
ln -s /usr/local/bin/python2.7 /usr/bin/python
cd ..


#安裝fabric模組
tar -xvf gmp-6.0.0a.tar.bz2
cd gmp-6.0.0
./configure
make
make check
make install
cd ..
tar -xvf  setuptools-30.2.0.tar.gz
cd setuptools-30.2.0
python setup.py build
python setup.py install
cd ..
tar -xvf pycrypto-2.6.1.tar.gz
cd pycrypto-2.6.1
export ac_cv_func_malloc_0_nonnull=yes
python setup.py build
python setup.py install
cd ..
tar -xvf pyasn1-0.1.9.tar.gz
cd pyasn1-0.1.9
python setup.py build
python setup.py install
cd ..
rpm -ivh libffi-devel-3.0.5-3.2.el6.x86_64.rpm
tar -xvf pycparser-2.17.tar.gz
cd pycparser-2.17
python setup.py build
python setup.py install
cd ..
tar -xvf cffi-1.9.1.tar.gz
cd cffi-1.9.1
python setup.py build
python setup.py install
cd ..
tar -xvf openssl-1.0.2.tar.gz
cd openssl-1.0.2
./config --prefix=/usr/local/openssl-1.0.2 shared zlib-dynamic enable-camellia
make && make install
ln -s /usr/lib64/libssl.so.1.0.1e /usr/lib64/libssl.so
ln -s /usr/lib64/libcrypto.so.1.0.1e /usr/lib64/libcrypto.so
cd ..
tar -xvf ipaddress-1.0.17.tar.gz
cd ipaddress-1.0.17
python setup.py build
python setup.py install
cd ..
tar -xvf enum34-1.1.6.tar.gz
cd enum34-1.1.6
python setup.py build
python setup.py install
cd ..
tar -xvf six-1.10.0.tar.gz
cd six-1.10.0
python setup.py build
python setup.py install
cd ..
tar -xvf idna-2.1.tar.gz
cd idna-2.1
python setup.py build
python setup.py install
cd ..
tar -xvf cryptography-1.6.tar.gz
cd cryptography-1.6
export C_INCLUDE_PATH=/usr/local/openssl-1.0.2/include
export CPLUS_INCLUDE_PATH=/usr/local/openssl-1.0.2/include
python setup.py build
python setup.py install
cd ..
tar -xvf ecdsa-0.13.tar.gz
cd ecdsa-0.13
python setup.py build
python setup.py install
cd ..
tar -xvf paramiko-1.15.2.tar.gz
cd paramiko-1.15.2
python setup.py build
python setup.py install
cd ..
tar -xvf Fabric-1.12.0.tar.gz
cd Fabric-1.12.0
python setup.py build
python setup.py install
cd ..

第二步:進入/home/fabric目錄,給install.sh檔案賦執行許可權,然後執行

cd/home/fabric

./install.sh

指令碼執行完成後檢視是否報錯,如果報錯根據錯誤資訊修正後,再執行指令碼。

在控制機上執行上面的命令,顯示出版本說明安裝成功

執行下面命令即可

python

>>>import_hashlib

第一步:將wrk-master.zip上傳到控制機的/home目錄下,執行解壓縮命令

cd/home

第二步:進入/home/wrk-master目錄,執行安裝命令

cdwrk-master

make

編譯完成之後會在/home/wrk-master目錄中生成wrk二進位制檔案。

第三步:上傳delayx.lua檔案到控制機的/home/wrk-master/scripts目錄下

delayx.lua檔案

function delay()
   return math.random(${thinktime}, ${thinktime})
end

第四步:上傳controller.py、ReadHost.py、clienthosts.txt三個檔案到控制機的/home目錄下

controller.py檔案

#!/usr/bin/python
# -*- coding:utf-8 -*-


from ReadHost import *
from fabric.api import *
from fabric.colors import *
from fabric.context_managers import *
from fabric.state import env
import re
import os
import sys
import datetime
#run test entrance,defin necessary parameter
def runtest():
    test_name="test_001" #test case name
    threads=4            #numbers of thread of every client host
    connections=4        #numbers of connection of every client host
    durations=10         #time of test case running
    thinktime=2000       #the time interval between requests
    url="http://10.41.150.52:8082/job/tcep/"  #request URL


    dt = datetime.datetime.now()
    res_file = "/home/test_result/%s_%s.txt"%(test_name,dt)
    res_file = res_file.replace(" ","_")
    if os.path.exists("/home/test_result"):
        with settings(hide('warnings', 'running', 'stdout', 'stderr'), warn_only=True):
            local("touch %s"%res_file)
    else:
        with settings(hide('warnings', 'running', 'stdout', 'stderr'), warn_only=True):
            local("mkdir /home/test_result&&touch %s"%res_file)
    with settings(hide('warnings', 'running', 'stdout', 'stderr'), warn_only=True):
        execute(runwrk,threads,connections,durations,url,test_name,thinktime,res_file)
    with open(res_file,'r') as f:
        counts = f.readlines() 
if counts:
  ltc = CountLTC(res_file)
  tps = CountTPS(res_file)
  io = CountIO(res_file)
  print yellow('Total => [90Percent Latancy:%s] [TPS:%s] [IO:%s]'%(ltc,tps,io))
  with settings(hide('warnings', 'running', 'stdout', 'stderr'), warn_only=True):
      local("echo 'Total => [90Percent Latancy:%s] [TPS:%s] [IO:%s]' >> %s"%(ltc,tps,io,res_file)) 
#get client host IP list
env.roledefs['wrk'] = HostList
#get client host password list
env.passwords = HostPswList
#get result function
def GetWrkResult(text):
    p1 = '.+?90%\s+(?P<latancy90>\d+\.?\d+\w+)'
    p2 = 'Requests/sec:\s+(?P<tps>\d+\.?\d+)'
    p3 = 'Transfer/sec:\s+(?P<tps_io>\d+\.?\d+\w+)'
    ret = {}
    m1 = re.search(p1,text)
    m2 = re.search(p2,text)
    m3 = re.search(p3,text)
    if m1:
    ret['latancy90'] = m1.group("latancy90")
    ret['tps'] = m2.group("tps")
    ret['io'] = m3.group("tps_io")
    return ret
#deploy wrk to all client host
@roles("wrk")
@parallel(pool_size=30)
def deploywrk():
    with settings(hide('warnings', 'running'), warn_only=True):
        run("mkdir -p /home/wrk-master/scripts")
        put("/home/wrk-master/wrk","/home/wrk-master/")
        run("chmod u+x /home/wrk-master/wrk")
        put("/home/wrk-master/scripts/*","/home/wrk-master/scripts/")
        
#begin to run wrk command in all client host
@roles("wrk")
@parallel
def runwrk(threads,connections,durations,url,test_name,thinktime,res_file):
    if threads>connections:
print red("%s:number of connections must be >= threads"%env.host)
return
    if thinktime:
        CMD = "./wrk -t{th} -c{con} -d{dur}s -T30s --script=./delay.lua --latency {test_url}".format(th=threads,con=connections,dur=durations,test_url=url)
    else:
        CMD = './wrk -t{th} -c{con} -d{dur}s -T30s --latency {test_url}'.format(th=threads,con=connections,dur=durations,test_url=url)
        host_speed_type = list(host_speed_type_define.keys())[list(host_speed_type_define.values()).index(env.host)]
        thinktime = speed_type_define[host_speed_type]
        
    WRKDIR = '/home/wrk-master/'
    with cd(WRKDIR):
        print green('%s:start testing with wrk ...'%env.host)
        run("export thinktime=%d&&envsubst '${thinktime}'<./scripts/delayx.lua >delay.lua"%thinktime)
        run(CMD + ">%s_%s.result"%(test_name,env.host))
        run("rm -f delay.lua")
        wrk_ret = GetWrkResult(run("cat %s_%s.result"%(test_name,env.host)))
if wrk_ret:
   tmp = '{wrkhost} => [90Percent Latancy:{latancy}] [TPS:{tps}] [IO:{io}] [URL:{test_url}]'.format(wrkhost = env.host,latancy = wrk_ret["latancy90"],tps = wrk_ret["tps"],io = wrk_ret["io"],test_url = url)
   local("echo '%s' >> %s"%(tmp,res_file))
            print yellow('{wrkhost} => [90Percent Latancy:{latancy}] [TPS:{tps}] [IO:{io}] [URL:{test_url}]'.format(wrkhost = env.host,latancy = wrk_ret["latancy90"],tps = wrk_ret["tps"],io = wrk_ret["io"],test_url = url))
else:
   print red("%s:test result is empty!"%env.host)


#count 90Percent Latancy average
def CountLTC(resultfile):
    with open(resultfile,'r') as f:
        reslist = f.readlines()  
        reslist = [ s[0] for s in [(res.split('Latancy:')[1].split('] [TPS')) for res in reslist]]
total = 0
for time in reslist:
   if time.count('us'):
total = total + float(time.split('.')[0])/1000
   else:
if time.count('ms'):
   total = total + float(time.split('ms')[0])
else:
   total = total + float(time.split('m')[0])*1000
        return str(round(total/len(reslist),2)) + 'ms'
#count total TPS
def CountTPS(resultfile):
    with open(resultfile,'r') as f:
        reslist = f.readlines()
        reslist = [ s[0] for s in [(res.split('[TPS:')[1].split('] [IO')) for res in reslist]]
        total = 0
        for tps in reslist:
            total = total + float(tps)
        return total
#count total IO
def CountIO(resultfile):
    with open(resultfile,'r') as f:
        reslist = f.readlines()
        reslist = [ s[0] for s in [(res.split('[IO:')[1].split('] [URL')) for res in reslist]]
        total = 0
containMB = False
for io in reslist:
            if io.count('MB'):
containMB = True
if containMB:
            for io in reslist:
if io.count('MB'):
                    total = total + float(io.split('MB')[0])
else:
   if io.count('KB'):
                        total = total + float(io.split('KB')[0])/1024 
else:
   for io in reslist:
   if io.count('KB'):
                    total = total + float(io.split('KB')[0])
if containMB:
   return str(round(total,2)) + 'MB'
else:
            return str(round(total,2)) + 'KB'

ReadHost.py檔案

#!/usr/bin/python
# -*- coding:utf-8 -*-
#read client host IP list from clienthost file
#format:['[email protected]:22', '[email protected]:22']
def GetHostList(hostfile):
    with open(hostfile,'r') as f:
        iplist = f.readlines()  
        iplist = [ '[email protected]' + s[0] + ':22' for s in [(ip.split('\t')) for ip in iplist]]
        return iplist
        
#read client host password list from clienthost file
#format:{ '[email protected]:22': 'c3E#6Jt(fB6PPj','[email protected]:22':'TNScP56m#nr2*K'}
def GetHostPswList(hostfile):
    with open(hostfile,'r') as f:
        iplist = f.readlines()  
        iplist = [(ip.split('\t')) for ip in iplist]
        psw_dic = {}
        for s in iplist:
            psw_dic['[email protected]' + s[0] + ':22'] = s[1].strip()
        return psw_dic


HostList = GetHostList("clienthosts.txt")
HostPswList = GetHostPswList("clienthosts.txt")


if __name__ == '__main__':
    print HostList
    print HostPswList

clienthosts.txt檔案

10.41.26.162 QEn68(Bmy$k7PW
10.41.26.164Rsf!QB7Qgj7A!3

2、部署壓力機

使用多臺機器作為壓力機,可以使用已經部署好的控制機來部署wrk到所有的壓力機。

(此步驟執行一次即可,如果要新增壓力機,需要再執行一次)

第一步:遠端登入控制機,進入/home 目錄

第二步:修改clienthosts.txt檔案,新增壓力機IP地址和對應的root登入密碼,格式如下:

10.41.150.50  AWd(g8hW(QYs62

10.41.150.51  ViLjBp858_H#yB

注意:1、IP和密碼之間用tab符隔開

2、最後一條記錄不要換行,即不能存在空行

第三步:執行命令fab -fcontroller.py deploywrk

執行命令過程檢查是否有報錯

二、   Wrk叢集壓測

1、wrk工具測試框架說明

使用1臺機器作為控制機(部署fabric,控制其他壓機機並行執行wrk指令碼,收集其他壓力機執行結果並在控制機顯示測試結果),使用多臺機器作為機器壓力測試機(部署wrk工具,執行wrk命令向伺服器傳送http/https請求);在所有壓力測試機上部署wrk工具或者執行wrk命令都是通過控制機的python指令碼controller.py 實現。

2、執行叢集併發測試

第一步:遠端登入控制機,進入/home 目錄

第二步:修改controller.py指令碼,根據需要修改下面的引數:

test_name=”test_001” 測試場景名稱,可以自定義

threads=4           每臺壓力機啟動執行緒數,最好和機器的CPU個數保持一致

connections=1000   每臺壓力機建立的連線數,必須大於或者等於啟動執行緒數

durations=60    測試指令碼執行時長,單位秒

thinktime= 2000  思考時間,每次請求的時間間隔,單位毫秒

url=”https://www.test.com/”   請求傳送的地址

執行過程監控是否有報錯

第四步:檢視測試結果,執行完成後控制機上會列印每臺壓力機的測試結果和總體統計結果

結果格式:壓機機ip => [百分之90響應時間][TPS] [每秒網路IO] [測試地址]

測試結果同時儲存在/home/test_result/目錄下面,檔名格式為:測試場景名稱_年月日_時分秒.txt