rabbitMQ学习六:队列性能测试及优化方法
性能测试
针对每个需要生产/消费者与rabbitmq进行通讯的方法进行测试
测试环境:
- 排除网络IO的干扰,采用生产者和消费者都在本地服务器的方式
- 内存16G,CPU4核,3.1GHZ
- 操作系统:oracle-linux
- python版本:3.6.3
测试内容
-
创建10万个connection连接的平均速度
-
创建10万个信道的平均速度
-
创建10万个相同队列的平均速度
-
创建10万个相同直连交换机的平均速度
-
创建10万个相同主题交换机的平均速度
-
创建10万个交换机和队列绑定的平均速度
-
投递10万条10字节消息的的平均速度
-
投递10万条300K消息的的平均速度
测试使用的脚本

#!/usr/bin/env python import threading import time import pika """这是队列生产者的客户端配置文件""" HOST = '192.168.1.22' PORT = '' MQ_NAME = 'eeg' FILENAME = './eeg2.txt' EXCHANGE = 'eegs' ROUT_KEY = 'eeg' USERNAME = 'passwd' PASSWD = 'passwd' class Client(object): def __init__(self, host, message, rout_key=ROUT_KEY, filename=FILENAME, queue_name=MQ_NAME, exchange=EXCHANGE, username=USERNAME, passwd=PASSWD): self.__message = message self.__host = host self.__rout = rout_key self.__filename = filename self.__username = username self.__queue_name = queue_name self.__exchange = exchange self.__passwd = passwd # 设置参数 def add_pars(self): # 添加用户名和密码 credentials = pika.PlainCredentials(self.__username, self.__passwd) # 配置连接参数 parameters = pika.ConnectionParameters( host=self.__host, credentials=credentials) return parameters # 连接mq队列 def connect_mq(self, parameters): try: # 创建一个连接对象 connection = pika.BlockingConnection(parameters) except Exception as e: print(e) else: return connection # 创建信道 def channel_mq(self, connection, prefetch=1): try: channel = connection.channel() # 公平调度 channel.basic_qos(prefetch_count=prefetch) except Exception as e: print(e) else: return channel # 声明一个队列 def queue_mq(self, channel, durable=True): try: result = channel.queue_declare( queue=self.__queue_name, durable=durable) print(result) except Exception as e: print(e) # 交换机队列绑定 def exchange_queue(self, channel): try: channel.queue_bind(exchange=self.__exchange, queue=self.__queue_name, routing_key=self.__rout) except Exception as e: print(e) # 投递一条消息 def message_mq(self, channel): try: result = channel.basic_publish(exchange=self.__exchange, routing_key=self.__rout, body=self.__message) if result: print(result) except Exception as e: print(e) # 创建一个直连交换机 def direct_exchange(self, channel, exchange_name): try: channel.exchange_declare(exchange=exchange_name, exchange_type='direct') except Exception as e: print(e) # 创建一个主题交换机 def topic_exchange(self, channel, exchange_name): try: channel.exchange_declare(exchange=exchange_name, exchange_type='topic', durable=False) except Exception as e: print(e) @staticmethod def open_data(filename): try: with open(filename, 'r', encoding='utf-8') as f: data = f.read() return data except Exception as e: print(e) # 测试时间装饰器 def test_nums(num=100): def test_time(func): def run(*args, **kwargs): time1 = time.time() for i in range(num): print(i) func(*args, **kwargs) time2 = time.time() print(num / (time2 - time1)) return run return test_time # 线程测试函数 def test_threads(func, nums, *args): for i in range(nums): # 21*5/s print(i) thread = threading.Thread(target=func, args=args) thread.start() # 在装饰器参数中加入需要测试的次数参数 # 测试创建1000条tcp连接的速度 @test_nums(100) def test_tcp(client, parameters): client.connect_mq(parameters) # 测试创建1000个信道的速度 @test_nums(100) def test_channel(client, con): client.channel_mq(con) # 测试声明1000个队列的速度 @test_nums(1000) def test_queue(client, channel): client.queue_mq(channel) # 测试声明1000个直连交换机的速度 @test_nums(100) def test_exchange(client, channel, name): client.direct_exchange(channel, name) # 测试声明1000个主题交换机的速度 @test_nums(100) def test_topic_exchange(client, channel, name): client.topic_exchange(channel, name) # 测试绑定交换机和队列的速度 @test_nums(100) def test_exchange_bind_queue(client, channel): client.exchange_queue(channel) # 测试投递消息的速度 @test_nums(100) def test_message(client, channel): client.message_mq(channel) if __name__ == '__main__': message = Client.open_data(FILENAME) client = Client(HOST, message) pars = client.add_pars() con = client.connect_mq(pars) channel = client.channel_mq(con) # client.direct_exchange(channel,'abc') # client.topic_exchange(channel,'topic_eeg') # 多线程测试# # 在test_threads函数中传递测试函数,线程数,函数参数。 # 测试连接tcp的速度 test_tcp(client, pars) # 15/s test_threads(test_tcp, 5, client, pars) # 21*5/s # 测试创建信道的速度 # test_channel(client,con) # 27/s # test_threads(test_channel, 5, client,con) # 21*5/s # 测试创建队列的速度 # test_queue(client,channel) # 55000msg/s # test_threads(test_queue, 5, client,channel) # 30000/s # 测试创建直连交换机的速度 # test_exchange(client,channel,'direct_eeg') # 单线程50msg/s # test_threads(test_exchange, 5, client,channel,'direct_eeg') # # 多线程10*5msg/s # 测试创建主题交换机的速度 # test_topic_exchange(client,channel,'topic_eeg') # 50/s # test_threads(test_topic_exchange, 5, client,channel,'topic_eeg') # # 多线程10*5msg/s # 测试绑定的速度 # test_exchange_bind_queue(client,channel) # 55/s # test_threads(test_exchange_bind_queue, 5, client,channel) # # 多线程10*5msg/s # 测试投递消息的速度 # test_message(client,channel) # 12msg/s
测试结果
connection连接:单线程496/s,多线程最大750/s 信道创建:单线程800/s,多线程850/s; 队列创建:单线程3867/s,多线程3300/s 交换机创建:单线程3900/s,多线程3250/s 绑定创建:单线程2700/s,多线程2500/s 10字节消息投递速度:10300msg/s 300k消息传递:2400msg/s
总结
-
可以看到信道的创建速度高于tcp连接,所以一般保持TCP连接而使用多个channel;
-
对于业务来说,一般是客户端请求服务器提交数据,服务器连接rabbitmq存储数据,那么服务器可以先创建tcp长连接池或channel信道池,到可以提交数据后,服务器直接调用连接对象传递数据。
-
队列和交换机一般是设置持久化的,它们可以长期存在,而消费者也是预先定义的,可以将队列的声明,交换机声明,绑定放在消费者端;
-
生产和消费同时消耗rabbitmq的资源,当生产消费不平衡,如生产大于消费造成消息堆积时,消费者的消费速度回随着内存的减小变慢,可能造成性能的急剧恶化;
测试发现的一个问题
使用pika操作rabbitmq,在创建信道池后,如果一段时间rabbitmq的tcp连接没有接受到请求,其会强制关闭tcp连接,造成信道池不可用,所以需要重新开启TCP连接;
参考
posted on 2019-02-01 17:21 myworldworld 阅读(708) 评论(0) 收藏 举报