Browse Source

Lithium: update and tune sql connections. (#5455)

* Lithium: update and tune sql connections.

* Lithium: Less sql connections.

* Lithium: Fix update.

* Lithium: Fix compilation.

* Lithium: Fix update.

* Lithium: Fix update.

* Lithium: Fix update.

* Lithium: Fix update.

* Lithium: Fix update.

* Lithium: Fix update.

* Lithium: Correcly flush postgres connections.

* Lithium: Faster tuning.

* Lithium: Fix tunning.

* Update lithium
Matthieu Garrigues 5 years ago
parent
commit
c09c9f5052

+ 4 - 3
frameworks/C++/lithium/lithium-mysql.dockerfile

@@ -5,11 +5,12 @@ RUN apt install -yqq libboost-dev libmariadb-dev wget  libboost-context-dev g++-
 
 COPY ./ ./
 
-ENV COMMIT=c63fddba232e490e151d2446e9ea20b189b15693
+ENV COMMIT=fff8ab327b905f89396b911e940e828dc8c6d742
 
 RUN wget https://raw.githubusercontent.com/matt-42/lithium/$COMMIT/single_headers/lithium_mysql.hh
 RUN wget https://raw.githubusercontent.com/matt-42/lithium/$COMMIT/single_headers/lithium_http_backend.hh
 
-RUN g++ -g -DTFB_MYSQL -O3 -march=native -std=c++17 ./lithium.cc -I /usr/include/mariadb -lpthread -lmariadbclient -lboost_context -o /lithium_tbf
+RUN g++ -DNDEBUG -g -DTFB_MYSQL -O3 -march=native -std=c++17 ./lithium.cc -I /usr/include/mariadb -lpthread -lmariadbclient -lboost_context -o /lithium_tbf
 
-CMD gdb -batch -x ./gdb.cmds --args /lithium_tbf tfb-database 8080
+#CMD gdb -batch -x ./gdb.cmds --args /lithium_tbf tfb-database 8080
+CMD /lithium_tbf tfb-database 8080

+ 1 - 1
frameworks/C++/lithium/lithium-postgres.dockerfile

@@ -5,7 +5,7 @@ RUN apt install -yqq g++-9 libboost-dev postgresql-server-dev-all libpq-dev wget
 
 COPY ./ ./
 
-ENV COMMIT=c63fddba232e490e151d2446e9ea20b189b15693
+ENV COMMIT=fff8ab327b905f89396b911e940e828dc8c6d742
 
 RUN wget https://raw.githubusercontent.com/matt-42/lithium/$COMMIT/single_headers/lithium_pgsql.hh
 RUN wget https://raw.githubusercontent.com/matt-42/lithium/$COMMIT/single_headers/lithium_http_backend.hh

+ 58 - 17
frameworks/C++/lithium/lithium.cc

@@ -33,6 +33,30 @@ void set_max_sql_connections_per_thread(int max)
 #endif
 }
 
+float tune_n_sql_connections(int& nc_to_tune, std::string http_req, int port, int max, int nprocs) {
+
+  std::cout << std::endl << "Benchmark " << http_req << std::endl;
+
+  float max_req_per_s = 0;
+  int best_nconn = 2;
+  for (int nc : {1, 2, 4, 8, 32, 64, 128})
+  {
+    if (nc*nprocs >= max) break;
+    nc_to_tune = nc;
+    float req_per_s = http_benchmark(256, 1, 300, port, http_req);
+    std::cout << nc << " -> " << req_per_s << " req/s." << std::endl;
+    if (req_per_s > max_req_per_s)
+    {
+      max_req_per_s = req_per_s;
+      best_nconn = nc;
+    }
+  }
+  std::cout << "best: " << best_nconn << " (" << max_req_per_s << " req/s)."<< std::endl;
+
+  return best_nconn;
+}
+
+
 int main(int argc, char* argv[]) {
 
   if (argc != 3)
@@ -48,17 +72,12 @@ int main(int argc, char* argv[]) {
   auto sql_db =
     mysql_database(s::host = argv[1], s::database = "hello_world", s::user = "benchmarkdbuser",
                    s::password = "benchmarkdbpass", s::port = 3306, s::charset = "utf8");
-  int mysql_max_connection = 256;
-  li::max_mysql_connections_per_thread = (mysql_max_connection / nprocs);
-  std::cout << "Using " << li::max_mysql_connections_per_thread << " connections per thread. " << nprocs << " threads." << std::endl; 
-
+  int sql_max_connection = sql_db.connect()("SELECT @@GLOBAL.max_connections;").template read<int>() - 10;
 #elif TFB_PGSQL
   auto sql_db =
     pgsql_database(s::host = argv[1], s::database = "hello_world", s::user = "benchmarkdbuser",
                    s::password = "benchmarkdbpass", s::port = 5432, s::charset = "utf8");
-  int pgsql_max_connection = 256;
-  li::max_pgsql_connections_per_thread = (pgsql_max_connection / nprocs);
-  std::cout << "Using " << li::max_pgsql_connections_per_thread << " connections per thread. " << nprocs << " threads." << std::endl; 
+  int sql_max_connection = atoi(sql_db.connect()("SHOW max_connections;").template read<std::string>().c_str()) - 10;
 #endif
 
   auto fortunes = sql_orm_schema(sql_db, "Fortune").fields(
@@ -69,6 +88,12 @@ int main(int argc, char* argv[]) {
     s::id(s::auto_increment, s::primary_key) = int(),
     s::randomNumber = int());
 
+
+  int db_nconn = 64;
+  int queries_nconn = 64;
+  int fortunes_nconn = 64;
+  int updates_nconn = 64;
+
   http_api my_api;
 
   my_api.get("/plaintext") = [&](http_request& request, http_response& response) {
@@ -80,18 +105,18 @@ int main(int argc, char* argv[]) {
     response.write_json(s::message = "Hello, World!");
   };
   my_api.get("/db") = [&](http_request& request, http_response& response) {
-    set_max_sql_connections_per_thread(64 / nprocs);
-    response.write_json(random_numbers.connect(request.yield).find_one(s::id = 1234).value());
+    set_max_sql_connections_per_thread(db_nconn);
+    response.write_json(random_numbers.connect(request.fiber).find_one(s::id = 1234).value());
   };
 
   my_api.get("/queries") = [&](http_request& request, http_response& response) {
-    set_max_sql_connections_per_thread(1);
+    set_max_sql_connections_per_thread(queries_nconn);
     std::string N_str = request.get_parameters(s::N = std::optional<std::string>()).N.value_or("1");
     int N = atoi(N_str.c_str());
     
     N = std::max(1, std::min(N, 500));
     
-    auto c = random_numbers.connect(request.yield);
+    auto c = random_numbers.connect(request.fiber);
     std::vector<decltype(random_numbers.all_fields())> numbers(N);
     for (int i = 0; i < N; i++)
       numbers[i] = c.find_one(s::id = 1 + rand() % 10000).value();
@@ -100,14 +125,14 @@ int main(int argc, char* argv[]) {
   };
 
   my_api.get("/updates") = [&](http_request& request, http_response& response) {
-    set_max_sql_connections_per_thread(1);
+    set_max_sql_connections_per_thread(updates_nconn);
     std::string N_str = request.get_parameters(s::N = std::optional<std::string>()).N.value_or("1");
     int N = atoi(N_str.c_str());
     N = std::max(1, std::min(N, 500));
     std::vector<decltype(random_numbers.all_fields())> numbers(N);
 
     {     
-      auto c = random_numbers.connect(request.yield);
+      auto c = random_numbers.connect(request.fiber);
       auto& raw_c = c.backend_connection();
 
       
@@ -144,12 +169,12 @@ int main(int argc, char* argv[]) {
   };
 
   my_api.get("/fortunes") = [&](http_request& request, http_response& response) {
-    set_max_sql_connections_per_thread(64 / nprocs);
+    set_max_sql_connections_per_thread(fortunes_nconn);
 
     typedef decltype(fortunes.all_fields()) fortune;
     std::vector<fortune> table;
 
-    auto c = fortunes.connect(request.yield);
+    auto c = fortunes.connect(request.fiber);
     c.forall([&] (auto f) { table.emplace_back(f); });
     table.emplace_back(0, "Additional fortune added at request time.");
 
@@ -172,8 +197,24 @@ int main(int argc, char* argv[]) {
     response.write(ss.to_string_view());
   };
 
-  http_serve(my_api, port, s::nthreads = nprocs);
+  // Tune the number of sql connections.
+  int tunning_port = port+1;
+  std::thread server_thread([&] {
+    http_serve(my_api, tunning_port, s::nthreads = nprocs);
+  });
+  usleep(3e5);
+
+  tune_n_sql_connections(db_nconn, "GET /db HTTP/1.1\r\n\r\n", tunning_port, sql_max_connection, nprocs);
+  tune_n_sql_connections(queries_nconn, "GET /queries?N=20 HTTP/1.1\r\n\r\n", tunning_port, sql_max_connection, nprocs);
+  tune_n_sql_connections(fortunes_nconn, "GET /fortunes HTTP/1.1\r\n\r\n", tunning_port, sql_max_connection, nprocs);
+  tune_n_sql_connections(updates_nconn, "GET /updates?N=20 HTTP/1.1\r\n\r\n", tunning_port, sql_max_connection, nprocs);
   
-  return 0;
+  li::quit_signal_catched = true;
+  server_thread.join();
+  li::quit_signal_catched = false;
+
+  // Start the server for the Techempower benchmark.
+  http_serve(my_api, port, s::nthreads = nprocs);
 
+  return 0;
 }