client_channel_stress_test.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. *
  3. * Copyright 2017 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include <atomic>
  19. #include <memory>
  20. #include <mutex>
  21. #include <random>
  22. #include <sstream>
  23. #include <string>
  24. #include <thread>
  25. #include "absl/memory/memory.h"
  26. #include "absl/strings/str_cat.h"
  27. #include <grpc/grpc.h>
  28. #include <grpc/support/alloc.h>
  29. #include <grpc/support/log.h>
  30. #include <grpc/support/time.h>
  31. #include <grpcpp/channel.h>
  32. #include <grpcpp/client_context.h>
  33. #include <grpcpp/create_channel.h>
  34. #include <grpcpp/impl/codegen/sync.h>
  35. #include <grpcpp/server.h>
  36. #include <grpcpp/server_builder.h>
  37. #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h"
  38. #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
  39. #include "src/core/lib/address_utils/parse_address.h"
  40. #include "src/core/lib/gprpp/ref_counted_ptr.h"
  41. #include "src/core/lib/gprpp/thd.h"
  42. #include "src/core/lib/iomgr/sockaddr.h"
  43. #include "src/core/lib/resolver/server_address.h"
  44. #include "src/core/lib/service_config/service_config_impl.h"
  45. #include "src/proto/grpc/lb/v1/load_balancer.grpc.pb.h"
  46. #include "src/proto/grpc/testing/echo.grpc.pb.h"
  47. #include "test/core/util/port.h"
  48. #include "test/core/util/test_config.h"
  49. #include "test/cpp/end2end/test_service_impl.h"
  50. using grpc::lb::v1::LoadBalancer;
  51. using grpc::lb::v1::LoadBalanceRequest;
  52. using grpc::lb::v1::LoadBalanceResponse;
  53. namespace grpc {
  54. namespace testing {
  55. namespace {
  56. const size_t kNumBackends = 10;
  57. const size_t kNumBalancers = 5;
  58. const size_t kNumClientThreads = 100;
  59. const int kResolutionUpdateIntervalMs = 50;
  60. const int kServerlistUpdateIntervalMs = 10;
  61. const int kTestDurationSec = 30;
  62. using BackendServiceImpl = TestServiceImpl;
  63. class BalancerServiceImpl : public LoadBalancer::Service {
  64. public:
  65. using Stream = ServerReaderWriter<LoadBalanceResponse, LoadBalanceRequest>;
  66. explicit BalancerServiceImpl(const std::vector<int>& all_backend_ports)
  67. : all_backend_ports_(all_backend_ports) {}
  68. Status BalanceLoad(ServerContext* /*context*/, Stream* stream) override {
  69. gpr_log(GPR_INFO, "LB[%p]: Start BalanceLoad.", this);
  70. LoadBalanceRequest request;
  71. stream->Read(&request);
  72. while (!shutdown_) {
  73. stream->Write(BuildRandomResponseForBackends());
  74. std::this_thread::sleep_for(
  75. std::chrono::milliseconds(kServerlistUpdateIntervalMs));
  76. }
  77. gpr_log(GPR_INFO, "LB[%p]: Finish BalanceLoad.", this);
  78. return Status::OK;
  79. }
  80. void Shutdown() { shutdown_ = true; }
  81. private:
  82. std::string Ip4ToPackedString(const char* ip_str) {
  83. struct in_addr ip4;
  84. GPR_ASSERT(inet_pton(AF_INET, ip_str, &ip4) == 1);
  85. return std::string(reinterpret_cast<const char*>(&ip4), sizeof(ip4));
  86. }
  87. LoadBalanceResponse BuildRandomResponseForBackends() {
  88. // Generate a random serverlist with varying size (if N =
  89. // all_backend_ports_.size(), num_non_drop_entry is in [0, 2N],
  90. // num_drop_entry is in [0, N]), order, duplicate, and drop rate.
  91. size_t num_non_drop_entry =
  92. std::rand() % (all_backend_ports_.size() * 2 + 1);
  93. size_t num_drop_entry = std::rand() % (all_backend_ports_.size() + 1);
  94. std::vector<int> random_backend_indices;
  95. for (size_t i = 0; i < num_non_drop_entry; ++i) {
  96. random_backend_indices.push_back(std::rand() % all_backend_ports_.size());
  97. }
  98. for (size_t i = 0; i < num_drop_entry; ++i) {
  99. random_backend_indices.push_back(-1);
  100. }
  101. std::shuffle(random_backend_indices.begin(), random_backend_indices.end(),
  102. std::mt19937(std::random_device()()));
  103. // Build the response according to the random list generated above.
  104. LoadBalanceResponse response;
  105. for (int index : random_backend_indices) {
  106. auto* server = response.mutable_server_list()->add_servers();
  107. if (index < 0) {
  108. server->set_drop(true);
  109. server->set_load_balance_token("load_balancing");
  110. } else {
  111. server->set_ip_address(Ip4ToPackedString("127.0.0.1"));
  112. server->set_port(all_backend_ports_[index]);
  113. }
  114. }
  115. return response;
  116. }
  117. std::atomic_bool shutdown_{false};
  118. const std::vector<int> all_backend_ports_;
  119. };
  120. class ClientChannelStressTest {
  121. public:
  122. void Run() {
  123. Start();
  124. // Keep updating resolution for the test duration.
  125. gpr_log(GPR_INFO, "Start updating resolution.");
  126. const auto wait_duration =
  127. std::chrono::milliseconds(kResolutionUpdateIntervalMs);
  128. std::vector<AddressData> addresses;
  129. auto start_time = std::chrono::steady_clock::now();
  130. while (true) {
  131. if (std::chrono::duration_cast<std::chrono::seconds>(
  132. std::chrono::steady_clock::now() - start_time)
  133. .count() > kTestDurationSec) {
  134. break;
  135. }
  136. // Generate a random subset of balancers.
  137. addresses.clear();
  138. for (const auto& balancer_server : balancer_servers_) {
  139. // Select each address with probability of 0.8.
  140. if (std::rand() % 10 < 8) {
  141. addresses.emplace_back(AddressData{balancer_server.port_, ""});
  142. }
  143. }
  144. std::shuffle(addresses.begin(), addresses.end(),
  145. std::mt19937(std::random_device()()));
  146. SetNextResolution(addresses);
  147. std::this_thread::sleep_for(wait_duration);
  148. }
  149. gpr_log(GPR_INFO, "Finish updating resolution.");
  150. Shutdown();
  151. }
  152. private:
  153. template <typename T>
  154. struct ServerThread {
  155. explicit ServerThread(const std::string& type,
  156. const std::string& server_host, T* service)
  157. : type_(type), service_(service) {
  158. grpc::internal::Mutex mu;
  159. // We need to acquire the lock here in order to prevent the notify_one
  160. // by ServerThread::Start from firing before the wait below is hit.
  161. grpc::internal::MutexLock lock(&mu);
  162. port_ = grpc_pick_unused_port_or_die();
  163. gpr_log(GPR_INFO, "starting %s server on port %d", type_.c_str(), port_);
  164. grpc::internal::CondVar cond;
  165. thread_ = absl::make_unique<std::thread>(
  166. std::bind(&ServerThread::Start, this, server_host, &mu, &cond));
  167. cond.Wait(&mu);
  168. gpr_log(GPR_INFO, "%s server startup complete", type_.c_str());
  169. }
  170. void Start(const std::string& server_host, grpc::internal::Mutex* mu,
  171. grpc::internal::CondVar* cond) {
  172. // We need to acquire the lock here in order to prevent the notify_one
  173. // below from firing before its corresponding wait is executed.
  174. grpc::internal::MutexLock lock(mu);
  175. std::ostringstream server_address;
  176. server_address << server_host << ":" << port_;
  177. ServerBuilder builder;
  178. builder.AddListeningPort(server_address.str(),
  179. InsecureServerCredentials());
  180. builder.RegisterService(service_);
  181. server_ = builder.BuildAndStart();
  182. cond->Signal();
  183. }
  184. void Shutdown() {
  185. gpr_log(GPR_INFO, "%s about to shutdown", type_.c_str());
  186. server_->Shutdown(grpc_timeout_milliseconds_to_deadline(0));
  187. thread_->join();
  188. gpr_log(GPR_INFO, "%s shutdown completed", type_.c_str());
  189. }
  190. int port_;
  191. std::string type_;
  192. std::unique_ptr<Server> server_;
  193. T* service_;
  194. std::unique_ptr<std::thread> thread_;
  195. };
  196. struct AddressData {
  197. int port;
  198. std::string balancer_name;
  199. };
  200. static grpc_core::ServerAddressList CreateAddressListFromAddressDataList(
  201. const std::vector<AddressData>& address_data) {
  202. grpc_core::ServerAddressList addresses;
  203. for (const auto& addr : address_data) {
  204. std::string lb_uri_str = absl::StrCat("ipv4:127.0.0.1:", addr.port);
  205. absl::StatusOr<grpc_core::URI> lb_uri = grpc_core::URI::Parse(lb_uri_str);
  206. GPR_ASSERT(lb_uri.ok());
  207. grpc_resolved_address address;
  208. GPR_ASSERT(grpc_parse_uri(*lb_uri, &address));
  209. grpc_arg arg = grpc_channel_arg_string_create(
  210. const_cast<char*>(GRPC_ARG_DEFAULT_AUTHORITY),
  211. const_cast<char*>(addr.balancer_name.c_str()));
  212. grpc_channel_args* args =
  213. grpc_channel_args_copy_and_add(nullptr, &arg, 1);
  214. addresses.emplace_back(address.addr, address.len, args);
  215. }
  216. return addresses;
  217. }
  218. static grpc_core::Resolver::Result MakeResolverResult(
  219. const std::vector<AddressData>& balancer_address_data) {
  220. grpc_core::Resolver::Result result;
  221. grpc_error_handle error = GRPC_ERROR_NONE;
  222. result.service_config = grpc_core::ServiceConfigImpl::Create(
  223. nullptr, "{\"loadBalancingConfig\":[{\"grpclb\":{}}]}", &error);
  224. GPR_ASSERT(error == GRPC_ERROR_NONE);
  225. grpc_core::ServerAddressList balancer_addresses =
  226. CreateAddressListFromAddressDataList(balancer_address_data);
  227. grpc_arg arg = CreateGrpclbBalancerAddressesArg(&balancer_addresses);
  228. result.args = grpc_channel_args_copy_and_add(nullptr, &arg, 1);
  229. return result;
  230. }
  231. void SetNextResolution(const std::vector<AddressData>& address_data) {
  232. grpc_core::ExecCtx exec_ctx;
  233. grpc_core::Resolver::Result result = MakeResolverResult(address_data);
  234. response_generator_->SetResponse(std::move(result));
  235. }
  236. void KeepSendingRequests() {
  237. gpr_log(GPR_INFO, "Start sending requests.");
  238. while (!shutdown_) {
  239. ClientContext context;
  240. context.set_deadline(grpc_timeout_milliseconds_to_deadline(1000));
  241. EchoRequest request;
  242. request.set_message("test");
  243. EchoResponse response;
  244. {
  245. std::lock_guard<std::mutex> lock(stub_mutex_);
  246. Status status = stub_->Echo(&context, request, &response);
  247. }
  248. }
  249. gpr_log(GPR_INFO, "Finish sending requests.");
  250. }
  251. void CreateStub() {
  252. ChannelArguments args;
  253. response_generator_ =
  254. grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
  255. args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
  256. response_generator_.get());
  257. std::ostringstream uri;
  258. uri << "fake:///servername_not_used";
  259. channel_ = grpc::CreateCustomChannel(uri.str(),
  260. InsecureChannelCredentials(), args);
  261. stub_ = grpc::testing::EchoTestService::NewStub(channel_);
  262. }
  263. void Start() {
  264. // Start the backends.
  265. std::vector<int> backend_ports;
  266. for (size_t i = 0; i < kNumBackends; ++i) {
  267. backends_.emplace_back(new BackendServiceImpl());
  268. backend_servers_.emplace_back(ServerThread<BackendServiceImpl>(
  269. "backend", server_host_, backends_.back().get()));
  270. backend_ports.push_back(backend_servers_.back().port_);
  271. }
  272. // Start the load balancers.
  273. for (size_t i = 0; i < kNumBalancers; ++i) {
  274. balancers_.emplace_back(new BalancerServiceImpl(backend_ports));
  275. balancer_servers_.emplace_back(ServerThread<BalancerServiceImpl>(
  276. "balancer", server_host_, balancers_.back().get()));
  277. }
  278. // Start sending RPCs in multiple threads.
  279. CreateStub();
  280. for (size_t i = 0; i < kNumClientThreads; ++i) {
  281. client_threads_.emplace_back(
  282. std::thread(&ClientChannelStressTest::KeepSendingRequests, this));
  283. }
  284. }
  285. void Shutdown() {
  286. shutdown_ = true;
  287. for (size_t i = 0; i < client_threads_.size(); ++i) {
  288. client_threads_[i].join();
  289. }
  290. for (size_t i = 0; i < balancers_.size(); ++i) {
  291. balancers_[i]->Shutdown();
  292. balancer_servers_[i].Shutdown();
  293. }
  294. for (size_t i = 0; i < backends_.size(); ++i) {
  295. backend_servers_[i].Shutdown();
  296. }
  297. }
  298. std::atomic_bool shutdown_{false};
  299. const std::string server_host_ = "localhost";
  300. std::shared_ptr<Channel> channel_;
  301. std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
  302. std::mutex stub_mutex_;
  303. std::vector<std::unique_ptr<BackendServiceImpl>> backends_;
  304. std::vector<std::unique_ptr<BalancerServiceImpl>> balancers_;
  305. std::vector<ServerThread<BackendServiceImpl>> backend_servers_;
  306. std::vector<ServerThread<BalancerServiceImpl>> balancer_servers_;
  307. grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
  308. response_generator_;
  309. std::vector<std::thread> client_threads_;
  310. };
  311. } // namespace
  312. } // namespace testing
  313. } // namespace grpc
  314. int main(int argc, char** argv) {
  315. grpc::testing::TestEnvironment env(argc, argv);
  316. grpc::testing::ClientChannelStressTest test;
  317. grpc_init();
  318. test.Run();
  319. grpc_shutdown();
  320. return 0;
  321. }