From 1e6509423ad875ab573c5e2a61b88f56d45f57a7 Mon Sep 17 00:00:00 2001 From: Niclas Antti Date: Thu, 26 Jul 2018 10:21:39 +0300 Subject: [PATCH] MXS-1777: Add an EMAverage to the server struct, and a new slave selection criteria. This is to support calculating the average from a session, and the slave selection criteria to be able to route based on averages. This commit, like the next one, have TODOs which you should feel free to comment on. Undecided things. --- include/maxscale/server.h | 17 +++++++++++++- maxutils/maxbase/src/average.cc | 4 +++- server/core/config.cc | 7 +++++- server/core/server.cc | 23 +++++++++++++++++++ .../routing/readwritesplit/readwritesplit.cc | 7 +++--- .../routing/readwritesplit/readwritesplit.hh | 10 ++++++-- 6 files changed, 60 insertions(+), 8 deletions(-) diff --git a/include/maxscale/server.h b/include/maxscale/server.h index 8e8e9af4d..0507d1d64 100644 --- a/include/maxscale/server.h +++ b/include/maxscale/server.h @@ -159,6 +159,9 @@ typedef struct server * by rwsplit. TODO: Move to rwsplit */ bool warn_ssl_not_enabled; /**< SSL not used for an SSL enabled server */ MxsDiskSpaceThreshold* disk_space_threshold; /**< Disk space thresholds */ + // TODO, this is a plain ptr to a C++ class. Soonish, when the server is new/deleted + // this will become a std::unique ptr. But not in this commit. + maxbase::EMAverage* response_time; /**< for calculating average response time */ } SERVER; /** @@ -444,6 +447,17 @@ json_t* server_list_to_json(const char* host); */ bool server_set_disk_space_threshold(SERVER *server, const char *disk_space_threshold); +/** + * @brief Add a response average to the server response average. + * + * @param server The server. + * @param ave Average. + * @param num_samples Number of samples the average consists of. + * + */ +void server_add_response_average(SERVER *server, double ave, int num_samples); + +extern int server_free(SERVER *server); extern SERVER *server_find_by_unique_name(const char *name); extern int server_find_by_unique_names(char **server_names, int size, SERVER*** output); extern SERVER *server_find(const char *servname, unsigned short port); @@ -455,7 +469,8 @@ extern void server_transfer_status(SERVER *dest_server, const SERVER *source_ser extern void server_add_mon_user(SERVER *server, const char *user, const char *passwd); extern size_t server_get_parameter(const SERVER *server, const char *name, char* out, size_t size); extern void server_update_credentials(SERVER *server, const char *user, const char *passwd); -extern DCB* server_get_persistent(SERVER *server, const char *user, const char* ip, const char *protocol, int id); +extern DCB* server_get_persistent(SERVER *server, const char *user, const char* ip, const char *protocol, + int id); extern void server_update_address(SERVER *server, const char *address); extern void server_update_port(SERVER *server, unsigned short port); extern uint64_t server_map_status(const char *str); diff --git a/maxutils/maxbase/src/average.cc b/maxutils/maxbase/src/average.cc index 242d1821f..bff3f7ab0 100644 --- a/maxutils/maxbase/src/average.cc +++ b/maxutils/maxbase/src/average.cc @@ -62,7 +62,9 @@ void CumulativeAverage::reset() } EMAverage::EMAverage(double min_alpha, double max_alpha, int sample_max) : - m_min_alpha{min_alpha}, m_max_alpha{max_alpha}, m_sample_max{sample_max} + m_min_alpha{min_alpha}, + m_max_alpha{max_alpha}, + m_sample_max{sample_max} { } diff --git a/server/core/config.cc b/server/core/config.cc index e0b245cd3..f6df90729 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -3608,6 +3608,11 @@ int create_new_server(CONFIG_CONTEXT *obj) } } + // nantti, TODO. Decide whether to expose some of this in config, or if the values + // can be calculated at runtime. The "500" or sample_max affects how often a + // session should updates this stat. sample_max should be slightly lower than max sample + // rate (which is less than qps due to the noise filter). + server->response_time = new (std::nothrow) maxbase::EMAverage(0.04, 0.35, 500); } else { @@ -4615,7 +4620,7 @@ bool get_suffixed_size(const char* value, uint64_t* dest) } bool config_parse_disk_space_threshold(MxsDiskSpaceThreshold* pDisk_space_threshold, - const char* zDisk_space_threshold) + const char* zDisk_space_threshold) { mxb_assert(pDisk_space_threshold); mxb_assert(zDisk_space_threshold); diff --git a/server/core/server.cc b/server/core/server.cc index 0dd825238..75505e779 100644 --- a/server/core/server.cc +++ b/server/core/server.cc @@ -28,6 +28,9 @@ #include #include #include +#include + +#include #include #include @@ -228,6 +231,7 @@ void server_free(Server* server) } delete server->disk_space_threshold; + delete server->response_time; delete server; } @@ -551,6 +555,18 @@ dprintServer(DCB *dcb, const SERVER *server) dcb_printf(dcb, "\tCurrent no. of conns: %d\n", server->stats.n_current); dcb_printf(dcb, "\tCurrent no. of operations: %d\n", server->stats.n_current_ops); dcb_printf(dcb, "\tNumber of routed packets: %lu\n", server->stats.packets); + std::ostringstream ave_os; + if (server->response_time->num_samples()) + { + maxbase::Duration dur(server->response_time->average()); + ave_os << dur; + } + else + { + ave_os << "not available"; + } + dcb_printf(dcb, "\tAverage response time: %s\n", ave_os.str().c_str()); + if (server->persistpoolmax) { dcb_printf(dcb, "\tPersistent pool size: %d\n", server->stats.n_persistent); @@ -1491,3 +1507,10 @@ bool server_set_disk_space_threshold(SERVER *server, const char *disk_space_thre return rv; } + +void server_add_response_average(SERVER *server, double ave, int num_samples) +{ + spinlock_acquire(&server->lock); + server->response_time->add(ave, num_samples); + spinlock_release(&server->lock); +} diff --git a/server/modules/routing/readwritesplit/readwritesplit.cc b/server/modules/routing/readwritesplit/readwritesplit.cc index c12fbb27d..90f81af4a 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.cc +++ b/server/modules/routing/readwritesplit/readwritesplit.cc @@ -86,14 +86,15 @@ static bool rwsplit_process_router_options(Config& config, char **options) select_criteria_t c = GET_SELECT_CRITERIA(value); mxb_assert(c == LEAST_GLOBAL_CONNECTIONS || c == LEAST_ROUTER_CONNECTIONS || c == LEAST_BEHIND_MASTER || - c == LEAST_CURRENT_OPERATIONS || c == UNDEFINED_CRITERIA); + c == LEAST_CURRENT_OPERATIONS || c == LOWEST_RESPONSE_TIME || + c == UNDEFINED_CRITERIA); if (c == UNDEFINED_CRITERIA) { MXS_ERROR("Unknown slave selection criteria \"%s\". " "Allowed values are LEAST_GLOBAL_CONNECTIONS, " - "LEAST_ROUTER_CONNECTIONS, LEAST_BEHIND_MASTER," - "and LEAST_CURRENT_OPERATIONS.", + "LEAST_ROUTER_CONNECTIONS, LEAST_BEHIND_MASTER, " + "LEAST_CURRENT_OPERATIONS and LOWEST_RESPONSE_TIME.", STRCRITERIA(config.slave_selection_criteria)); success = false; } diff --git a/server/modules/routing/readwritesplit/readwritesplit.hh b/server/modules/routing/readwritesplit/readwritesplit.hh index 18c606d3f..0ef1e7532 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.hh +++ b/server/modules/routing/readwritesplit/readwritesplit.hh @@ -66,7 +66,7 @@ enum select_criteria_t LEAST_ROUTER_CONNECTIONS, /**< connections established by this router */ LEAST_BEHIND_MASTER, LEAST_CURRENT_OPERATIONS, - DEFAULT_CRITERIA = LEAST_CURRENT_OPERATIONS, + LOWEST_RESPONSE_TIME, LAST_CRITERIA /**< not used except for an index */ }; @@ -103,6 +103,7 @@ static const MXS_ENUM_VALUE slave_selection_criteria_values[] = {"LEAST_ROUTER_CONNECTIONS", LEAST_ROUTER_CONNECTIONS}, {"LEAST_BEHIND_MASTER", LEAST_BEHIND_MASTER}, {"LEAST_CURRENT_OPERATIONS", LEAST_CURRENT_OPERATIONS}, + {"LOWEST_RESPONSE_TIME", LOWEST_RESPONSE_TIME}, {NULL} }; @@ -134,7 +135,9 @@ static const MXS_ENUM_VALUE master_failure_mode_values[] = strncmp(s,"LEAST_ROUTER_CONNECTIONS", strlen("LEAST_ROUTER_CONNECTIONS")) == 0 ? \ LEAST_ROUTER_CONNECTIONS : ( \ strncmp(s,"LEAST_CURRENT_OPERATIONS", strlen("LEAST_CURRENT_OPERATIONS")) == 0 ? \ - LEAST_CURRENT_OPERATIONS : UNDEFINED_CRITERIA)))) + LEAST_CURRENT_OPERATIONS : ( \ + strncmp(s,"LOWEST_RESPONSE_TIME", strlen("LOWEST_RESPONSE_TIME")) == 0 ? \ + LOWEST_RESPONSE_TIME : UNDEFINED_CRITERIA))))) #define BACKEND_TYPE(b) (server_is_master((b)->backend_server) ? BE_MASTER : \ (server_is_slave((b)->backend_server) ? BE_SLAVE : BE_UNDEFINED)); @@ -337,6 +340,9 @@ static inline const char* select_criteria_to_str(select_criteria_t type) case LEAST_CURRENT_OPERATIONS: return "LEAST_CURRENT_OPERATIONS"; + case LOWEST_RESPONSE_TIME: + return "LOWEST_RESPONSE_TIME"; + default: return "UNDEFINED_CRITERIA"; }