37.1 QPS测试

Lars/api/cpp/example/qps.cpp

  1. #include <stdlib.h>
  2. #include <iostream>
  3. #include <pthread.h>
  4. #include "lars_api.h"
  5. struct ID
  6. {
  7. int t_id;
  8. int modid;
  9. int cmdid;
  10. };
  11. void *test_qps(void *args)
  12. {
  13. int ret = 0;
  14. ID *id = (ID*)args;
  15. int modid = id->modid;
  16. int cmdid = id->cmdid;
  17. lars_client api;
  18. std::string ip;
  19. int port;
  20. //qps记录
  21. long qps = 0;
  22. //记录最后时间
  23. long last_time = time(NULL);
  24. long total_qps = 0;
  25. long total_time_second = 0;
  26. //1. lars_api 初始化(只调用一次)
  27. ret = api.reg_init(modid, cmdid);
  28. if (ret != 0) {
  29. std::cout << "modid " << modid << ", cmdid " << cmdid << " still not exist host, after register, ret = " << ret << std::endl;
  30. }
  31. while (1) {
  32. ret = api.get_host(modid, cmdid, ip, port);
  33. if (ret == 0 || ret == 1 || ret == 3) { // 成功,过载,不存在 均是合法返回
  34. ++qps;
  35. if (ret == 0) {
  36. api.report(modid, cmdid, ip, port, 0);//上报成功
  37. }
  38. else if (ret == 1) {
  39. api.report(modid, cmdid, ip, port, 1);//上报过载
  40. }
  41. }
  42. else {
  43. printf("[%d,%d] get error %d\n", modid, cmdid, ret);
  44. }
  45. //当前时间
  46. long current_time = time(NULL);
  47. if (current_time - last_time >= 1) {
  48. total_time_second += 1;
  49. total_qps += qps;
  50. last_time = current_time;
  51. printf("thread:[%d] --> qps = [%ld], average = [%ld]\n", id->t_id, qps, total_qps/total_time_second);
  52. qps = 0;
  53. }
  54. }
  55. return NULL;
  56. }
  57. int main(int argc, char **argv)
  58. {
  59. if (argc != 2) {
  60. printf("./qps [thread_num]\n");
  61. return 1;
  62. }
  63. int cnt = atoi(argv[1]);
  64. ID *ids = new ID[cnt];
  65. pthread_t *tids = new pthread_t[cnt];
  66. //制作模拟的modid/cmdid
  67. for (int i = 0; i < cnt; i++) {
  68. ids[i].t_id = i;
  69. ids[i].modid = i + 1;
  70. ids[i].cmdid = 1;
  71. }
  72. for (int i = 0; i < cnt; i++) {
  73. pthread_create(&tids[i], NULL, test_qps, &ids[i]);
  74. }
  75. for (int i = 0; i < cnt; i++) {
  76. pthread_join(tids[i], NULL);
  77. }
  78. return 0;
  79. }

37.2 测试结果

  1. 分别启动Lars-ReporterLars-DnsLars-LB-Agent三个service服务

看客户端运行结果

  1. $ ./qps 1
  2. thread:[0] --> qps = [4594], average = [4594]
  3. thread:[0] --> qps = [5159], average = [4876]
  4. thread:[0] --> qps = [5190], average = [4981]
  5. thread:[0] --> qps = [5039], average = [4995]
  6. thread:[0] --> qps = [4949], average = [4986]
  7. thread:[0] --> qps = [5111], average = [5007]
  8. thread:[0] --> qps = [5075], average = [5016]
  9. thread:[0] --> qps = [5067], average = [5023]
  10. thread:[0] --> qps = [5104], average = [5032]
  11. thread:[0] --> qps = [4976], average = [5026]
  12. thread:[0] --> qps = [5022], average = [5026]
  13. thread:[0] --> qps = [5088], average = [5031]
  14. thread:[0] --> qps = [5114], average = [5037]
  15. thread:[0] --> qps = [5072], average = [5040]
  16. thread:[0] --> qps = [4808], average = [5024]
  17. thread:[0] --> qps = [5119], average = [5030]
  18. thread:[0] --> qps = [5055], average = [5031]
  19. thread:[0] --> qps = [5026], average = [5031]
  20. thread:[0] --> qps = [5040], average = [5032]
  21. thread:[0] --> qps = [4931], average = [5026]
  22. thread:[0] --> qps = [5073], average = [5029]
  23. ...
  1. 这里我们客户端是开启一个线程进行测试,平均每秒服务端会响应5000次左右。
  2. 这里我简单用两个主机,分别测试了一些数据

主机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

  1. #include "lars_api.h"
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <time.h>
  5. #include <map>
  6. void usage()
  7. {
  8. printf("usage: ./simulator ModID CmdID [errRate(0-10)] [query cnt(0-999999)]\n");
  9. }
  10. int main(int argc, char **argv)
  11. {
  12. int ret = 0;
  13. if (argc < 3) {
  14. usage();
  15. return 1;
  16. }
  17. int modid = atoi(argv[1]);
  18. int cmdid = atoi(argv[2]);
  19. int err_rate = 2;
  20. int query_cnt = 100;
  21. if (argc > 3) {
  22. err_rate = atoi(argv[3]);
  23. }
  24. if (argc > 4) {
  25. query_cnt = atoi(argv[4]);
  26. }
  27. lars_client api;
  28. std::string ip;
  29. int port;
  30. //key---ip, value---<succ_cnt, err_cnt>
  31. std::map<std::string, std::pair<int, int>> result;
  32. std::cout << "err_rate = " << err_rate << std::endl;
  33. //1. lars_api 初始化(只调用一次)
  34. ret = api.reg_init(modid, cmdid);
  35. if (ret != 0) {
  36. std::cout << "modid " << modid << ", cmdid " << cmdid << " still not exist host, after register, ret = " << ret << std::endl;
  37. }
  38. srand(time(NULL));
  39. for (int i = 0; i < query_cnt; i++) {
  40. ret = api.get_host(modid, cmdid, ip, port);
  41. if (ret == 0) {
  42. //获取成功
  43. if (result.find(ip) == result.end()) {
  44. // 首次获取当前ip
  45. std::pair<int ,int> succ_err(0, 0);
  46. result[ip] = succ_err;
  47. }
  48. std::cout << "host " << ip << ":" << "host" << "called ";
  49. if (rand()%10 < err_rate) {// 80%的几率产生调用失败
  50. result[ip].second += 1;
  51. api.report(modid, cmdid, ip, port, 1);
  52. std::cout << " ERROR!!!" << std::endl;
  53. }
  54. else {
  55. result[ip].first += 1;
  56. api.report(modid, cmdid, ip, port, 0);
  57. std::cout << " SUCCESS." << std::endl;
  58. }
  59. }
  60. else if (ret == 3) {
  61. std::cout << modid << "," << cmdid << " not exist" << std::endl;
  62. }
  63. else if (ret == 2) {
  64. std::cout << "system err" << std::endl;
  65. }
  66. else if (ret == 1) {
  67. std::cout << modid << "," << cmdid << " all hosts were overloaded!!!" << std::endl;
  68. }
  69. else {
  70. std::cout << "get error code " << ret << std::endl;
  71. }
  72. usleep(6000);
  73. }
  74. //遍历结果
  75. std::map<std::string, std::pair<int, int>>::iterator it;
  76. for (it = result.begin(); it != result.end(); it ++) {
  77. std::cout <<"ip : " << it->first << ": ";
  78. std::cout <<"success: " << it->second.first << "; ";
  79. std::cout <<"error: " << it->second.second << std::endl;
  80. }
  81. return 0;
  82. }

37.3 get_host测试工具

Lars/api/cpp/example/get_host.cpp

  1. #include "lars_api.h"
  2. #include <iostream>
  3. void usage()
  4. {
  5. printf("usage: ./get_host [modid] [cmdid]\n");
  6. }
  7. int main(int argc, char **argv)
  8. {
  9. int ret = 0;
  10. if (argc != 3) {
  11. usage();
  12. return 1;
  13. }
  14. int modid = atoi(argv[1]);
  15. int cmdid = atoi(argv[2]);
  16. lars_client api;
  17. std::string ip;
  18. int port;
  19. //1. lars_api 初始化(只调用一次)
  20. ret = api.reg_init(modid, cmdid);
  21. if (ret != 0) {
  22. std::cout << "modid " << modid << ", cmdid " << cmdid << " still not exist host, after register, ret = " << ret << std::endl;
  23. }
  24. //2. 获取一个host的ip+port
  25. ret = api.get_host(modid, cmdid, ip, port);
  26. if (ret == 0) {
  27. std::cout << "host is " << ip << ":" << port << std::endl;
  28. }
  29. return 0;
  30. }

37.4 get_route测试工具

Lars/api/cpp/example/get_route.cpp

  1. #include "lars_api.h"
  2. #include <iostream>
  3. void usage()
  4. {
  5. printf("usage: ./get_route [modid] [cmdid]\n");
  6. }
  7. int main(int argc, char **argv)
  8. {
  9. int ret = 0;
  10. if (argc != 3) {
  11. usage();
  12. return 1;
  13. }
  14. int modid = atoi(argv[1]);
  15. int cmdid = atoi(argv[2]);
  16. lars_client api;
  17. //1. lars_api 初始化(只调用一次)
  18. ret = api.reg_init(modid, cmdid);
  19. if (ret != 0) {
  20. std::cout << "modid " << modid << ", cmdid " << cmdid << " still not exist host, after register, ret = " << ret << std::endl;
  21. }
  22. //2. 获取modid/cmdid下全部的host的ip+port
  23. route_set route;
  24. ret = api.get_route(modid, cmdid, route);
  25. if (ret == 0) {
  26. for (route_set_it it = route.begin(); it != route.end(); it++) {
  27. std::cout << "ip = " << (*it).first << ", port = " << (*it).second << std::endl;
  28. }
  29. }
  30. return 0;
  31. }

37.5 reporter测试工具

Lars/api/cpp/example/report.cpp

  1. #include "lars_api.h"
  2. #include <iostream>
  3. void usage()
  4. {
  5. printf("usage: ./report ModID CmdID IP Port 0|1 --- 0:succ, 1:overload \n");
  6. }
  7. int main(int argc, char **argv)
  8. {
  9. int ret = 0;
  10. if (argc != 6) {
  11. usage();
  12. return 1;
  13. }
  14. int modid = atoi(argv[1]);
  15. int cmdid = atoi(argv[2]);
  16. std::string ip = argv[3];
  17. int port = atoi(argv[4]);
  18. int ret_code = atoi(argv[5]);
  19. lars_client api;
  20. //1. lars_api 初始化(只调用一次)
  21. ret = api.reg_init(modid, cmdid);
  22. if (ret != 0) {
  23. std::cout << "modid " << modid << ", cmdid " << cmdid << " still not exist host, after register, ret = " << ret << std::endl;
  24. }
  25. api.report(modid, cmdid, ip, port, ret_code);
  26. std::string result = (ret_code == 0)? "SUCC" :"OVERLOAD";
  27. std::cout << "report modid = " << modid << ", cmdid = " << cmdid << " | " << ip << ":" << port << " " << result << std::endl;
  28. return 0;
  29. }

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弄巧成拙的在这方面防止了这个情况(本来只想用他防止一上来就失败过载的情况)