Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C++] Introduce userver #7617

Merged
merged 17 commits into from
Nov 27, 2022
38 changes: 38 additions & 0 deletions frameworks/C++/userver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# userver Benchmarking Test

This is the [userver](https://github.com/userver-framework/userver) portion of a [benchmarking test suite](https://github.com/TechEmpower/FrameworkBenchmarks) comparing a variety of web development platforms.

### Test Type Implementation Source Code

* [PLAINTEXT](userver_benchmark/src/controllers/plaintext/handler.cpp)
* [JSON](userver_benchmark/src/controllers/json/handler.cpp)
* [Single Database Query](userver_benchmark/src/controllers/single_query/handler.cpp)
* [Multiple Database Queries](userver_benchmark/src/controllers/multiple_queries/handler.cpp)
* [Database Updates](userver_benchmark/src/controllers/updates/handler.cpp)
* [Cached Queries](userver_benchmark/src/controllers/cached_queries/handler.cpp)

## Test URLs
### PLAINTEXT

http://localhost:8080/plaintext

### JSON

http://localhost:8080/json

### Single Database Query

http://localhost:8080/db

### Multiple Database Queries

http://localhost:8080/queries

### Database Updates

http://localhost:8080/updates

### Cached Queries

http://localhost:8080/cached-queries

30 changes: 30 additions & 0 deletions frameworks/C++/userver/benchmark_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"framework": "userver",
"tests": [
{
"default": {
"json_url": "/json",
"plaintext_url": "/plaintext",
"db_url": "/db",
"query_url": "/queries?queries=",
"update_url": "/updates?queries=",
"cached_query_url": "/cached-queries?count=",
"port": 8080,
"approach": "Realistic",
"classification": "Micro",
"database": "postgres",
"framework": "userver",
"language": "C++",
"flavor": "None",
"orm": "Raw",
"platform": "None",
"webserver": "None",
"os": "Linux",
"database_os": "Linux",
"display_name": "userver",
"notes": "",
"versus": "None"
}
}
]
}
17 changes: 17 additions & 0 deletions frameworks/C++/userver/userver.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM ghcr.io/userver-framework/docker-userver-build-base:v1a
WORKDIR src
COPY userver_benchmark/src/ ./
RUN git clone https://github.com/userver-framework/userver.git && \
cd userver && git checkout 84456123a6a32f68847a791f29ef56d86bb765ad
RUN mkdir build && cd build && \
cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_OPEN_SOURCE_BUILD=1 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 \
-DUSERVER_FEATURE_REDIS=0 -DUSERVER_FEATURE_CLICKHOUSE=0 -DUSERVER_FEATURE_MONGODB=0 -DUSERVER_FEATURE_RABBITMQ=0 -DUSERVER_FEATURE_GRPC=0 \
-DUSERVER_FEATURE_UTEST=0 \
-DUSERVER_FEATURE_POSTGRESQL=1 \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native" .. && \
make -j $(nproc)

COPY userver_benchmark/configs/* ./

EXPOSE 8090
CMD ./build/userver_techempower -c /src/static_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"USERVER_CACHES": {},
"USERVER_CANCEL_HANDLE_REQUEST_BY_DEADLINE": false,
"USERVER_CHECK_AUTH_IN_HANDLERS": false,
"USERVER_DUMPS": {},
"USERVER_HTTP_PROXY": "",
"USERVER_LOG_REQUEST": false,
"USERVER_LOG_REQUEST_HEADERS": false,
"USERVER_LRU_CACHES": {},
"USERVER_RPS_CCONTROL_CUSTOM_STATUS": {},
"USERVER_TASK_PROCESSOR_PROFILER_DEBUG": {},
"HTTP_CLIENT_CONNECTION_POOL_SIZE": 1000,
"HTTP_CLIENT_CONNECT_THROTTLE": {
"http-limit": 6000,
"http-per-second": 1500,
"https-limit": 100,
"https-per-second": 25,
"per-host-limit": 3000,
"per-host-per-second": 500
},
"HTTP_CLIENT_ENFORCE_TASK_DEADLINE": {
"cancel-request": false,
"update-timeout": false
},
"USERVER_TASK_PROCESSOR_QOS": {
"default-service": {
"default-task-processor": {
"wait_queue_overload": {
"action": "ignore",
"length_limit": 16385,
"time_limit_us": 30000
}
}
}
},

"POSTGRES_STATEMENT_METRICS_SETTINGS": {},
"POSTGRES_CONNECTION_PIPELINE_ENABLED": false,
"POSTGRES_CONNECTION_POOL_SETTINGS": {
"hello_world": {
"max_pool_size": 512,
"max_queue_size": 512,
"min_pool_size": 256
}
},
"POSTGRES_CONNECTION_SETTINGS": {},
"POSTGRES_DEFAULT_COMMAND_CONTROL": {
"network_timeout_ms": 1750,
"statement_timeout_ms": 1500
},
"POSTGRES_HANDLERS_COMMAND_CONTROL": {},
"POSTGRES_QUERIES_COMMAND_CONTROL": {}
}
12 changes: 12 additions & 0 deletions frameworks/C++/userver/userver_benchmark/configs/secure_data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"postgresql_settings": {
"databases": {
"hello_world": [{
"shard_number" : 0,
"hosts": [
"postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world"
]
}]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# yaml
components_manager:
coro_pool:
initial_size: 10000 # Preallocate 10000 coroutines at startup.
max_size: 65536 # Do not keep more than 65536 preallocated coroutines.
stack_size: 66560 # 64Kb for coroutine stack

task_processors: # Task processor is an executor for coroutine tasks

main-task-processor: # Make a task processor for CPU-bound couroutine tasks.
thread_name: main-worker # OS will show the threads of this task processor with 'main-worker' prefix.
worker_threads: 26
guess-cpu-limit: true

fs-task-processor: # Make a separate task processor for filesystem bound tasks.
thread_name: fs-worker
worker_threads: 4

default_task_processor: main-task-processor

components: # Configuring components that were registered via component_list
server:
listener: # configuring the main listening socket...
port: 8080 # ...to listen on this port and...
task_processor: main-task-processor # ...process incoming requests on this task processor.
logging:
fs-task-processor: fs-task-processor
loggers:
default:
file_path: '@stderr'
level: ERROR
overflow_behavior: discard # Drop logs if the system is too busy to write them down.

tracer: # Component that helps to trace execution times and requests in logs.
service-name: userver-techempower # "You know. You all know exactly who I am. Say my name. " (c)

dynamic-config: # Dynamic config storage options, do nothing
fs-cache-path: ''
dynamic-config-fallbacks: # Load options from file and push them into the dynamic config storage.
fallback-path: /src/dynamic_config_fallback.json

testsuite-support:

secdist: # Component that stores configuration of hosts and passwords
config: /src/secure_data.json # Values are supposed to be stored in this file
missing-ok: false # ... but if the file is missing it is still ok

plaintext-handler:
path: /plaintext
method: GET
task_processor: main-task-processor

json-handler:
path: /json
method: GET
task_processor: main-task-processor

hello-world-db:
dbalias: hello_world
blocking_task_processor: fs-task-processor
min_pool_size: 20
max_pool_size: 520
max_queue_size: 500

single-query-handler:
path: /db
method: GET
task_processor: main-task-processor

multiple-queries-handler:
path: /queries
method: GET
task_processor: main-task-processor

updates-handler:
path: /updates
method: GET
task_processor: main-task-processor

world-pg-cache:
pgcomponent: hello-world-db
update-types: only-full
update-interval: 1s
update-correction: 50ms

cached-queries-handler:
path: /cached-queries
method: GET
task_processor: main-task-processor

17 changes: 17 additions & 0 deletions frameworks/C++/userver/userver_benchmark/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.12)
project(userver_techempower CXX)

set(CMAKE_CXX_STANDARD 17)

file(GLOB_RECURSE SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/controllers/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/common/*.cpp
)

include(userver/cmake/SetupEnvironment.cmake)
include(GNUInstallDirs)

add_subdirectory(userver)

add_executable(${PROJECT_NAME} ${SOURCES} userver_techempower.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE userver-core userver-postgresql)
38 changes: 38 additions & 0 deletions frameworks/C++/userver/userver_benchmark/src/common/db_helpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include "db_helpers.hpp"

#include <userver/formats/json/inline.hpp>
#include <userver/utils/rand.hpp>

namespace userver_techempower::db_helpers {

int GenerateRandomId() {
return userver::utils::RandRange(1, kMaxWorldRows + 1);
}

int GenerateRandomValue() {
return userver::utils::RandRange(1, kMaxWorldRows + 1);
}

userver::formats::json::Value Serialize(
const WorldTableRow& value,
userver::formats::serialize::To<userver::formats::json::Value>) {
return userver::formats::json::MakeObject("id", value.id, "randomNumber",
value.random_number);
}

int ParseParamFromQuery(const userver::server::http::HttpRequest& request,
const std::string& name) {
const auto& arg_str = request.GetArg(name);
if (arg_str.empty()) {
return 1;
}

try {
int value = std::stoi(arg_str);
return std::min(500, std::max(1, value));
} catch (const std::invalid_argument&) {
return 1;
}
}

} // namespace userver_techempower::db_helpers
32 changes: 32 additions & 0 deletions frameworks/C++/userver/userver_benchmark/src/common/db_helpers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include <userver/formats/json/value.hpp>
#include <userver/server/http/http_request.hpp>
#include <userver/storages/postgres/cluster_types.hpp>
#include <userver/storages/postgres/query.hpp>

namespace userver_techempower::db_helpers {

constexpr int kMaxWorldRows = 10000;
const userver::storages::postgres::Query kSelectRowQuery{
"SELECT id, randomNumber FROM World WHERE id = $1"};
constexpr auto kClusterHostType =
userver::storages::postgres::ClusterHostType::kMaster;
constexpr std::string_view kDbComponentName = "hello-world-db";

struct WorldTableRow final {
int id;
int random_number;
};

int GenerateRandomId();
int GenerateRandomValue();

userver::formats::json::Value Serialize(
const WorldTableRow& value,
userver::formats::serialize::To<userver::formats::json::Value>);

int ParseParamFromQuery(const userver::server::http::HttpRequest& request,
const std::string& name);

} // namespace userver_techempower::db_helpers
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "handler.hpp"

#include <userver/formats/serialize/common_containers.hpp>

#include <boost/container/small_vector.hpp>

namespace userver_techempower::cached_queries {

Handler::Handler(const userver::components::ComponentConfig& config,
const userver::components::ComponentContext& context)
: userver::server::handlers::HttpHandlerJsonBase{config, context},
cache_{context.FindComponent<WorldCacheComponent>()},
query_arg_name_{"count"} {}

userver::formats::json::Value Handler::HandleRequestJsonThrow(
const userver::server::http::HttpRequest& request,
const userver::formats::json::Value&,
userver::server::request::RequestContext&) const {
const auto queries_count =
db_helpers::ParseParamFromQuery(request, query_arg_name_);

boost::container::small_vector<db_helpers::WorldTableRow, 500> result(
queries_count);

const auto cache_ptr = cache_.Get();
const auto& cache = *cache_ptr;
std::generate(result.begin(), result.end(),
[&cache] { return cache.at(db_helpers::GenerateRandomId()); });

return userver::formats::json::ValueBuilder{result}.ExtractValue();
}

} // namespace userver_techempower::cached_queries
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include <userver/server/handlers/http_handler_json_base.hpp>

#include "world_cache_component.hpp"

namespace userver_techempower::cached_queries {

class Handler final : public userver::server::handlers::HttpHandlerJsonBase {
public:
static constexpr std::string_view kName = "cached-queries-handler";

Handler(const userver::components::ComponentConfig& config,
const userver::components::ComponentContext& context);

userver::formats::json::Value HandleRequestJsonThrow(
const userver::server::http::HttpRequest& request,
const userver::formats::json::Value&,
userver::server::request::RequestContext&) const final;

private:
const WorldCacheComponent& cache_;

const std::string query_arg_name_;
};

} // namespace userver_techempower::cached_queries
Loading