压力测试工具是软件测试过程中的必用工具,而压力测试工具如何控制流量大小呢?
最常见的是计算每个请求之间的时间间隔,然后通过sleep方法来让两次请求产生间隔。这种方法有2个缺点,sleep时会让线程挂起,所以需要比较多的线程数;其二,当流量非常大的情况,比如qps达到10万以上时,会收到系统时钟精度和线程上下文切换的挑战。
本文设计了另外一种方法,底层原理为时间轮算法,利用二进制的与操作来实现。按照概率控制流量大小。但概率的计算并不依赖随机数,而是通过设置一个概率控制变量的方法,让流量的发送更加均衡。
代码如下:
class Transformer {
public:
Transformer() :
send_num(0),
qps(0),
benchmark(0),
counter(0),
thread_pool(10) {}
void run();
void stop() { tc.stop(); }
private:
void sendOne();
void transform();
int32_t send_num;
int32_t qps;
int32_t benchmark;
std::atomic counter;
ThreadPool thread_pool;
TimerController tc;
};
void Transformer::run() {
qps = FLAGS_qps;
if (qps <= 0 || qps > 1e5) {
return;
}
int32_t query = (qps << 16) / 1000;
send_num = query >> 16;
query &= 0xFFFF;
for (int i = 0; i < 16; ++i) {
benchmark <<= 1;
if (query & 1) {
++benchmark;
}
query >>= 1;
}
tc.cycleProcess(1, [this]() { this->transform(); });
}
void Transformer::transform() {
uint32_t cur_c = counter.fetch_add(1, std::memory_order_relaxed);
cur_c &= 0xFFFF;
if (cur_c <= 0) {
return;
}
int32_t delta = 0;
for (int i = 0,bit = 1; i < 16; ++i, bit <<= 1) {
if ((cur_c & bit) == 0) {
continue;
}
if ((benchmark & bit) == 0) {
break;
} else {
delta = 1;
break;
}
}
int32_t cur_send_num = send_num + delta;
if (cur_send_num <= 0) {
return;
}
for (int i = 0; i< cur_send_num; ++i) {
thread_pool.enqueue([this]() { this->sendOne(); });
}
}