[python运维] 使用python3制作一个mysql压测小工具!

308 阅读6分钟

0x01 argparse模块

argparse是Python 标准库中推荐的命令行解析模块,他可以实现给出参数提示和接收用户输入的参数,类似linux的命令行功能:

[root@yunweisn ~]# grep
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
[root@yunweisn ~]# grep --help
Usage: grep [OPTION]... PATTERN [FILE]...
Search for PATTERN in each FILE or standard input.
PATTERN is, by default, a basic regular expression (BRE).
Example: grep -i 'hello world' menu.h main.c

Regexp selection and interpretation:
  -E, --extended-regexp     PATTERN is an extended regular expression (ERE)
  -F, --fixed-strings       PATTERN is a set of newline-separated fixed strings

argparse快速入门:

#!/usr/bin/python3
import argparse
parse = argparse.ArgumentParser(description='this is test script') # 实例化
# description 描述信息
parse.add_argument('-t','--test',dest='teststr',action='store',
                    type=str,default='testing...',help='test help string') # 增加一个参数
# -t 短参数
# --test 长参数
# dest 后续引用的变量名,不写默认是长参数名称
# action有6种,不指定默认为store
# type 默认为str,常见的还有int
# default 参数的默认值
# help 用户使用help命令时显示的信息
args = parse.parse_args() # 接收用户输入的参数
print(args.teststr)


# 运行1
[root@yunweisn testdemo]# python3 testdemo01.py --help
usage: testdemo01.py [-h] [-t TESTSTR]

this is test script # 描述信息

optional arguments:
  -h, --help            show this help message and exit # 默认有个help参数
  -t TESTSTR, --test TESTSTR # 参数名称
                        test help string # 参数帮助


# 运行2
[root@yunweisn testdemo]# python3 testdemo01.py
testing...
[root@yunweisn testdemo]# python3 testdemo01.py -t 123
123

argparse有6种action

  1. store 保存参数值,可能会先将参数值转换成另一个数据类型。若没有显式指定动作,则默认为该动作。

  2. store_const 保存一个被定义为参数规格一部分的值,而不是一个来自参数解析而来的值。这通常用于实现非布尔值的命令行标记。

  3. store_ture/store_false 保存相应的布尔值。这两个动作被用于实现布尔开关。

  4. append 将值保存到一个列表中。若参数重复出现,则保存多个值。

  5. append_const 将一个定义在参数规格中的值保存到一个列表中。

  6. version 打印关于程序的版本信息,然后退出


0x02 来打造一个类mysql命令行客户端工具

先看看mysql命令默认是如何提示的?

[root@yunweisn ~]# mysql
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

# 这里可见执行mysql的时候,有两个默认参数 
# -u 用户名
# -h 主机名

python实现类似功能如下:

import argparse
import commands

def main():
    parse = argparse.ArgumentParser(description='mysql client tools')
    parse.add_argument('-u','--user',dest='username',default='root',action='store_true',help='login to mysql username')
    parse.add_argument('-H','--host',dest='hostname',default='localhost',action='store_true',help='login to mysql server hostname')
    args = parse.parse_args()
    cmd = "mysql -u{} -p{}".format(args.username, args.hostname)
    print(commands.getoutput(cmd))


if __name__ == '__main__':
    main()
# 运行01
[root@yunweisn testdemo]# python3 mysql-client01.py 
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

0x03 pymysql模块

pymysql用于在python中连接和操作mysql数据库。

快速入门:

#!/usr/bin/python3
import pymysql

def main():
    # 创建连接
    conn = pymysql.connect(host='localhost,user='root',password='root',port=3306)
    # 创建一个游标
    cursor = conn.cursor()
    # 执行sql语句
    cursor.execute('show processlist;')
    # 获取所有的返回值
    print(cursor.fetchall())
    # 关闭
    conn.close()

    if __name__ == '__main__':
    main()

0x04 faker模块伪造数据

faker可以生成一些看起来比较真实的数据

>>> from faker import Faker
>>> faker = Faker("zh_CN")
>>> faker.name()
'莫玉珍'
>>> faker.job()
'人事经理'
>>> faker.address()
'甘肃省郑州市海港兰路E座 158840'

0x05 简单实现一下插入数据

#!/usr/bin/python3
#conding=utf-8
import argparse
import pymysql
from faker import Faker 
import sys

def args_list():
    parse = argparse.ArgumentParser('connect to mysql tools')
    parse.add_argument("--host",dest='hostname',action='store',default='localhost',help='mysql server hostname.')
    parse.add_argument("-u","--user",dest='username',action='store',default='root',help='connect to mysql server user.')
    parse.add_argument("-p","--password",dest='password',action='store',help='connect to mysql server password.')
    parse.add_argument("-P","--port",dest='port',action='store',default=3306,type=int,help='mysql server port.')
    parse.add_argument("-n","--linenumber",dest='linenumber',default=5,type=int,help='insert data line')

    args = parse.parse_args()
    return args


def conn_db(**kwargs):
    try:
        # 连接数据库
        conn = pymysql.connect(**kwargs)
        return conn # 返回conn
    except Exception as err:
        print("连接数据库错误,err=",err)
        sys.exit(1)
def create_table(cursor):
    sql = """
        create table if not exists `test`.`test001` (id int(10) not null auto_increment,
        name varchar(255) not null,
        job varchar(255) not null,
        address varchar(255) not null,
        primary key (`id`))
    """
    try:
        cursor.execute(sql)
    except Exception as err:
        print("创建表test001错误,err=",err)
        sys.exit(2)

def insert_data(cursor,linenumber,faker):
    for i in range(linenumber): # 根据用户输入的行数插入数据
        name = faker.name() # 生成名字
        job = faker.job()  # 生成职业
        address = faker.address() # 生成地址
        # 拼接sql语句
        sql = """
            insert into `test`.`test001`(name,job,address)
            values('{0}','{1}','{2}')
        """.format(name,job,address)
        print(sql)
        # 执行sql
        cursor.execute(sql)
def main():
    faker = Faker("zh_CN") # 实例化faker
    args = args_list() # 获取用户输入的信息
    #连接数据库 --> conn_db
    conn = conn_db(**dict(host=args.hostname,user=args.username,password=args.password,port=args.port))
    # 创建游标
    cursor = conn.cursor()
    # 创建表 --> create_table 
    create_table(cursor)
    # 插入数据
    insert_data(cursor,args.linenumber,faker)


if __name__ == '__main__':
    main()



#运行01
[root@yunweisn testdemo]# python3 pymysql-test02.py --host ssh.51yunwei.top -utestuser -pTestUser@123 -n 5

            insert into `test`.`test001`(name,job,address)
            values('陈秀兰','其他','河北省柳州市闵行东莞街H座 663475')


            insert into `test`.`test001`(name,job,address)
            values('陈成','学徒工','海南省上海市华龙农路H座 901586')


            insert into `test`.`test001`(name,job,address)
            values('金金凤','药品生产/质量管理','河南省莹县清浦崔街H座 341881')


            insert into `test`.`test001`(name,job,address)
            values('刘斌','汽车修理工','台湾省桂花县涪城赵路e座 673426')


            insert into `test`.`test001`(name,job,address)
            values('雷超','射频工程师','吉林省瑞市高港南宁路I座 464175')


# 登陆到数据库里看看
MariaDB [test]> select * from test001;
+----+-----------+---------------------------+----------------------------------------------+
| id | name      | job                       | address                                      |
+----+-----------+---------------------------+----------------------------------------------+
|  1 | 陈秀兰    | 其他                      | 河北省柳州市闵行东莞街H座 663475             |
|  2 | 陈成      | 学徒工                    | 海南省上海市华龙农路H座 901586               |
|  3 | 金金凤    | 药品生产/质量管理         | 河南省莹县清浦崔街H座 341881                 |
|  4 | 刘斌      | 汽车修理工                | 台湾省桂花县涪城赵路e座 673426               |
|  5 | 雷超      | 射频工程师                | 吉林省瑞市高港南宁路I座 464175               |
+----+-----------+---------------------------+----------------------------------------------+
5 rows in set (0.00 sec)

0x06 加上多进程,小工具出炉!

#!/usr/bin/python3
#conding=utf-8
import argparse
import pymysql
from faker import Faker 
import sys
import threading

def args_list():
    parse = argparse.ArgumentParser('connect to mysql tools')
    parse.add_argument("--host",dest='hostname',action='store',default='localhost',help='mysql server hostname. default localhost')
    parse.add_argument("-u","--user",dest='username',action='store',default='root',help='connect to mysql server user. default root')
    parse.add_argument("-p","--password",dest='password',action='store',help='connect to mysql server password.')
    parse.add_argument("-P","--port",dest='port',action='store',default=3306,type=int,help='mysql server port. default 3306')
    parse.add_argument("-n","--linenumber",dest='linenumber',default=500,type=int,help='insert data line , default 500')
   # 添加一个线程数量的选项
    parse.add_argument("-t","--thread_size",dest='thread_size',default=5,type=int,help='thread number,default 5')

    args = parse.parse_args()
    return args


def conn_db(**kwargs):
    try:
        conn = pymysql.connect(**kwargs)
        return conn
    except Exception as err:
        print("连接数据库错误,err=",err)
        sys.exit(1)


def create_table(cursor):
    sql = """
        create table if not exists `test`.`test001` (id int(10) not null auto_increment,
        name varchar(255) not null,
        job varchar(255) not null,
        address varchar(255) not null,
        primary key (`id`)) character set = utf8
    """
    try:
        cursor.execute(sql)
    except Exception as err:
        print("创建表test001错误,err=",err)
        sys.exit(2)

def insert_data(conn_dict,linenumber,faker):
    # 为每个线程都创建一个conn,避免资源争用
    conn = conn_db(**conn_dict)
    cursor = conn.cursor()
    for i in range(linenumber):
        name = faker.name()
        job = faker.job()
        address = faker.address()
        sql = """
            insert into `test`.`test001`(name,job,address)
            values('{0}','{1}','{2}')
        """.format(name,job,address)
        print(sql)
        cursor.execute(sql)
    cursor.execute('commit')
    # 线程操作完成后提交并关闭链接
    cursor.close()
    conn.close()
def main():
    faker = Faker("zh_CN")
    args = args_list()
    conn_dict = dict(host=args.hostname,user=args.username,password=args.password,port=args.port)
    conn = conn_db(**dict(host=args.hostname,user=args.username,password=args.password,port=args.port))
    cursor = conn.cursor()
    create_table(cursor)
    # 创建表后关闭链接
    cursor.close()
    conn.close()

    threads = [] 
    for i in range(args.thread_size):
        t = threading.Thread(target=insert_data,args=(conn_dict, args.linenumber,faker))
        threads.append(t)
        t.start()
    for t in threads:# 进程阻塞,避免未执行完成主进程退出
        t.join() 


if __name__ == '__main__':
    main()

# 运行01
[root@yunweisn testdemo]# python3 pymysql-test02.py --host localhost -uroot -proot -t 5 -n 500
......
# 查看结果
MariaDB [test]> select count(*) from test001;
+----------+
| count(*) |
+----------+
|     2530 |
+----------+
1 row in set (0.00 sec)

图片

本文使用 文章同步助手 同步