37.1 QPS测试
Lars/api/cpp/example/qps.cpp
#include <stdlib.h>#include <iostream>#include <pthread.h>#include "lars_api.h"struct ID{int t_id;int modid;int cmdid;};void *test_qps(void *args){int ret = 0;ID *id = (ID*)args;int modid = id->modid;int cmdid = id->cmdid;lars_client api;std::string ip;int port;//qps记录long qps = 0;//记录最后时间long last_time = time(NULL);long total_qps = 0;long total_time_second = 0;//1. lars_api 初始化(只调用一次)ret = api.reg_init(modid, cmdid);if (ret != 0) {std::cout << "modid " << modid << ", cmdid " << cmdid << " still not exist host, after register, ret = " << ret << std::endl;}while (1) {ret = api.get_host(modid, cmdid, ip, port);if (ret == 0 || ret == 1 || ret == 3) { // 成功,过载,不存在 均是合法返回++qps;if (ret == 0) {api.report(modid, cmdid, ip, port, 0);//上报成功}else if (ret == 1) {api.report(modid, cmdid, ip, port, 1);//上报过载}}else {printf("[%d,%d] get error %d\n", modid, cmdid, ret);}//当前时间long current_time = time(NULL);if (current_time - last_time >= 1) {total_time_second += 1;total_qps += qps;last_time = current_time;printf("thread:[%d] --> qps = [%ld], average = [%ld]\n", id->t_id, qps, total_qps/total_time_second);qps = 0;}}return NULL;}int main(int argc, char **argv){if (argc != 2) {printf("./qps [thread_num]\n");return 1;}int cnt = atoi(argv[1]);ID *ids = new ID[cnt];pthread_t *tids = new pthread_t[cnt];//制作模拟的modid/cmdidfor (int i = 0; i < cnt; i++) {ids[i].t_id = i;ids[i].modid = i + 1;ids[i].cmdid = 1;}for (int i = 0; i < cnt; i++) {pthread_create(&tids[i], NULL, test_qps, &ids[i]);}for (int i = 0; i < cnt; i++) {pthread_join(tids[i], NULL);}return 0;}
37.2 测试结果
分别启动Lars-Reporter、Lars-Dns、Lars-LB-Agent三个service服务
看客户端运行结果
$ ./qps 1thread:[0] --> qps = [4594], average = [4594]thread:[0] --> qps = [5159], average = [4876]thread:[0] --> qps = [5190], average = [4981]thread:[0] --> qps = [5039], average = [4995]thread:[0] --> qps = [4949], average = [4986]thread:[0] --> qps = [5111], average = [5007]thread:[0] --> qps = [5075], average = [5016]thread:[0] --> qps = [5067], average = [5023]thread:[0] --> qps = [5104], average = [5032]thread:[0] --> qps = [4976], average = [5026]thread:[0] --> qps = [5022], average = [5026]thread:[0] --> qps = [5088], average = [5031]thread:[0] --> qps = [5114], average = [5037]thread:[0] --> qps = [5072], average = [5040]thread:[0] --> qps = [4808], average = [5024]thread:[0] --> qps = [5119], average = [5030]thread:[0] --> qps = [5055], average = [5031]thread:[0] --> qps = [5026], average = [5031]thread:[0] --> qps = [5040], average = [5032]thread:[0] --> qps = [4931], average = [5026]thread:[0] --> qps = [5073], average = [5029]...
这里我们客户端是开启一个线程进行测试,平均每秒服务端会响应5000次左右。这里我简单用两个主机,分别测试了一些数据
主机1:
CPU个数:2个 , 内存: 2GB , 系统:Ubuntu18.04虚拟机
| 线程数 | QPS |
|---|---|
| 1 | 0.5w/s |
| 2 | 2.2w/s |
| 10 | 5.5w/s |
| 100 | 5.3w/s |
主机2:
CPU个数: 24个 , 内存:128GB, 系统: 云主机
| 线程数 | QPS |
|---|---|
| 1 | 8.36w/s |
| 3 | 28.06w/s |
| 5 | 55.18w/s |
| 8 | 56.74w/s |
37.2 Lars模拟器系统测试
Lars/api/cpp/example/simulator.cpp
#include "lars_api.h"#include <iostream>#include <stdlib.h>#include <time.h>#include <map>void usage(){printf("usage: ./simulator ModID CmdID [errRate(0-10)] [query cnt(0-999999)]\n");}int main(int argc, char **argv){int ret = 0;if (argc < 3) {usage();return 1;}int modid = atoi(argv[1]);int cmdid = atoi(argv[2]);int err_rate = 2;int query_cnt = 100;if (argc > 3) {err_rate = atoi(argv[3]);}if (argc > 4) {query_cnt = atoi(argv[4]);}lars_client api;std::string ip;int port;//key---ip, value---<succ_cnt, err_cnt>std::map<std::string, std::pair<int, int>> result;std::cout << "err_rate = " << err_rate << std::endl;//1. lars_api 初始化(只调用一次)ret = api.reg_init(modid, cmdid);if (ret != 0) {std::cout << "modid " << modid << ", cmdid " << cmdid << " still not exist host, after register, ret = " << ret << std::endl;}srand(time(NULL));for (int i = 0; i < query_cnt; i++) {ret = api.get_host(modid, cmdid, ip, port);if (ret == 0) {//获取成功if (result.find(ip) == result.end()) {// 首次获取当前ipstd::pair<int ,int> succ_err(0, 0);result[ip] = succ_err;}std::cout << "host " << ip << ":" << "host" << "called ";if (rand()%10 < err_rate) {// 80%的几率产生调用失败result[ip].second += 1;api.report(modid, cmdid, ip, port, 1);std::cout << " ERROR!!!" << std::endl;}else {result[ip].first += 1;api.report(modid, cmdid, ip, port, 0);std::cout << " SUCCESS." << std::endl;}}else if (ret == 3) {std::cout << modid << "," << cmdid << " not exist" << std::endl;}else if (ret == 2) {std::cout << "system err" << std::endl;}else if (ret == 1) {std::cout << modid << "," << cmdid << " all hosts were overloaded!!!" << std::endl;}else {std::cout << "get error code " << ret << std::endl;}usleep(6000);}//遍历结果std::map<std::string, std::pair<int, int>>::iterator it;for (it = result.begin(); it != result.end(); it ++) {std::cout <<"ip : " << it->first << ": ";std::cout <<"success: " << it->second.first << "; ";std::cout <<"error: " << it->second.second << std::endl;}return 0;}
37.3 get_host测试工具
Lars/api/cpp/example/get_host.cpp
#include "lars_api.h"#include <iostream>void usage(){printf("usage: ./get_host [modid] [cmdid]\n");}int main(int argc, char **argv){int ret = 0;if (argc != 3) {usage();return 1;}int modid = atoi(argv[1]);int cmdid = atoi(argv[2]);lars_client api;std::string ip;int port;//1. lars_api 初始化(只调用一次)ret = api.reg_init(modid, cmdid);if (ret != 0) {std::cout << "modid " << modid << ", cmdid " << cmdid << " still not exist host, after register, ret = " << ret << std::endl;}//2. 获取一个host的ip+portret = api.get_host(modid, cmdid, ip, port);if (ret == 0) {std::cout << "host is " << ip << ":" << port << std::endl;}return 0;}
37.4 get_route测试工具
Lars/api/cpp/example/get_route.cpp
#include "lars_api.h"#include <iostream>void usage(){printf("usage: ./get_route [modid] [cmdid]\n");}int main(int argc, char **argv){int ret = 0;if (argc != 3) {usage();return 1;}int modid = atoi(argv[1]);int cmdid = atoi(argv[2]);lars_client api;//1. lars_api 初始化(只调用一次)ret = api.reg_init(modid, cmdid);if (ret != 0) {std::cout << "modid " << modid << ", cmdid " << cmdid << " still not exist host, after register, ret = " << ret << std::endl;}//2. 获取modid/cmdid下全部的host的ip+portroute_set route;ret = api.get_route(modid, cmdid, route);if (ret == 0) {for (route_set_it it = route.begin(); it != route.end(); it++) {std::cout << "ip = " << (*it).first << ", port = " << (*it).second << std::endl;}}return 0;}
37.5 reporter测试工具
Lars/api/cpp/example/report.cpp
#include "lars_api.h"#include <iostream>void usage(){printf("usage: ./report ModID CmdID IP Port 0|1 --- 0:succ, 1:overload \n");}int main(int argc, char **argv){int ret = 0;if (argc != 6) {usage();return 1;}int modid = atoi(argv[1]);int cmdid = atoi(argv[2]);std::string ip = argv[3];int port = atoi(argv[4]);int ret_code = atoi(argv[5]);lars_client api;//1. lars_api 初始化(只调用一次)ret = api.reg_init(modid, cmdid);if (ret != 0) {std::cout << "modid " << modid << ", cmdid " << cmdid << " still not exist host, after register, ret = " << ret << std::endl;}api.report(modid, cmdid, ip, port, ret_code);std::string result = (ret_code == 0)? "SUCC" :"OVERLOAD";std::cout << "report modid = " << modid << ", cmdid = " << cmdid << " | " << ip << ":" << port << " " << result << std::endl;return 0;}
FAQ
init_succ = 180,err_rate = 0.1
而 : 10succ+21err 才过载,实际失败率并不是0.1啊?
答:
实际上,观察一组数据:
10succ+21err 过载 实际rate=67%
20succ+22err 过载 实际rate=50%
……
90succ + 30err 过载 实际rate=25%
……
200succ + 42err 过载,实际rate=17%
……
500succ + 75err 过载,实际rate=13%
即量越大越接近我们设定的=10%
而量越小,失败率更大才会导致过载
这样的设计是很好的,因为量小的时候不应该武断的认为10%就过载,比如10succ+2err就会过载,才失败了两次,但是达到了10%,所以过载了,这是很不合理的
我们的init_succ弄巧成拙的在这方面防止了这个情况(本来只想用他防止一上来就失败过载的情况)
