diff --git a/README.md b/README.md index 51e45ab..e759450 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Atlas is a MySQL protocol-based database middleware project developed and mainta ### 5.Requirement and feedback -If You have new functional requirements about Atlas in the production environment, or find a bug in the process of using Atlas. Welcome to send a mail to g-atlas@360.cn, we will reply as soon as possible. Also you can contact us in [Google group](https://groups.google.com/forum/#!forum/atlas-proxy). Enthusiastic user has established a QQ group:326544838, the developers of Atlas have also been in the QQ group. +If You have new functional requirements about Atlas in the production environment, or find a bug in the process of using Atlas. Welcome to send a mail to g-atlas[at]360.cn, we will reply as soon as possible. Also you can contact us in [Google group](https://groups.google.com/forum/#!forum/atlas-proxy). Enthusiastic user has established a QQ group:326544838, the developers of Atlas have also been in the QQ group. ### 6.The origin of the name diff --git a/README_ZH.md b/README_ZH.md index 2eea989..73da456 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -1,7 +1,7 @@ 我们团队开发了另外一个有意思的项目 pika, pika 是一个兼容redis 协议的大容量的存储, 用来解决redis 内存不够的问题, 欢迎大家试试 -由于团队精力有限, 目前Atlas 依据满足了公司大部分的需求, 因此很多Issue 我们很难再继续满足. 但是我们欢迎社区里面喜欢Atlas, 愿意给Atlas 做贡献的小伙伴可以一起来改善Atlas, 给Atlas 提交代码. 欢迎联系 chenzongzhi@360.cn +由于团队精力有限, 目前Atlas 依据满足了公司大部分的需求, 因此很多Issue 我们很难再继续满足. 但是我们欢迎社区里面喜欢Atlas, 愿意给Atlas 做贡献的小伙伴可以一起来改善Atlas, 给Atlas 提交代码. 欢迎联系 g-infra@360.cn! ### 一、简介 diff --git a/example.cnf b/example.cnf new file mode 100644 index 0000000..8b7c2dd --- /dev/null +++ b/example.cnf @@ -0,0 +1,22 @@ +[mysql-proxy] +admin-username=admin +admin-password=admin_password +admin-lua-script=/usr/local/mysql-proxy/lib/mysql-proxy/lua/admin.lua +log-level=message +log-path=./log +plugin-dir=./lib +daemon=false +keepalive=false +event-threads=2 +instance=3470 +proxy-address=0.0.0.0:13470 +admin-address=0.0.0.0:23470 +proxy-backend-addresses=192.168.1.1:3306 +proxy-read-only-backend-addresses=192.168.1.2:3306 +client-ips=127.0.0.1,192.168.1,192.168.2.35 +lvs-ips=192.168.0.1 +pwds=user_name:user_password +charset=utf8 +sql-log=ON +max_conn_for_a_backend=0 +wait-timeout=60 diff --git a/plugins/proxy/proxy-plugin.c b/plugins/proxy/proxy-plugin.c index c9b20ca..9e1cbfe 100644 --- a/plugins/proxy/proxy-plugin.c +++ b/plugins/proxy/proxy-plugin.c @@ -2103,6 +2103,16 @@ NETWORK_MYSQLD_PLUGIN_PROTO(proxy_disconnect_client) { st->backend->connected_clients--; } */ + + if (st && st->backend) { + if (!g_atomic_int_compare_and_exchange(&st->backend->connected_clients, 0, 0)) { + g_atomic_int_dec_and_test(&st->backend->connected_clients); + } + //g_critical("last in proxy_disconnect_client: %08x's connected_clients is %d\n", st->backend, st->backend->connected_clients); + } + + + #ifdef HAVE_LUA_H /* remove this cached script from registry */ if (st->L_ref > 0) { diff --git a/src/chassis-mainloop.h b/src/chassis-mainloop.h index b40b58d..195a462 100644 --- a/src/chassis-mainloop.h +++ b/src/chassis-mainloop.h @@ -69,6 +69,8 @@ struct chassis { chassis_stats_t *stats; /**< the overall chassis stats, includes lua and glib allocation stats */ + gint max_conn_for_a_backend; + /* network-io threads */ guint event_thread_count; diff --git a/src/mysql-proxy-cli.c b/src/mysql-proxy-cli.c index 56c2bdc..cce59ed 100644 --- a/src/mysql-proxy-cli.c +++ b/src/mysql-proxy-cli.c @@ -127,6 +127,8 @@ typedef struct { gint max_files_number; + gint max_conn_for_a_backend; + gint event_thread_count; gchar *log_level; @@ -152,6 +154,7 @@ chassis_frontend_t *chassis_frontend_new(void) { frontend->event_thread_count = 1; frontend->max_files_number = 0; frontend->wait_timeout = 0; + frontend->max_conn_for_a_backend = 0; return frontend; } @@ -201,7 +204,8 @@ int chassis_frontend_set_chassis_options(chassis_frontend_t *frontend, chassis_o chassis_options_add(opts, "lua-cpath", 0, 0, G_OPTION_ARG_STRING, &(frontend->lua_cpath), "set the LUA_CPATH", "<...>"); chassis_options_add(opts, "instance", 0, 0, G_OPTION_ARG_STRING, &(frontend->instance_name), "instance name", ""); chassis_options_add(opts, "wait-timeout", 0, 0, G_OPTION_ARG_INT, &(frontend->wait_timeout), "the number of seconds which Atlas waits for activity on a connection before closing it (default:0)", NULL); - + chassis_options_add(opts, "max_conn_for_a_backend", 0, 0, G_OPTION_ARG_INT, &(frontend->max_conn_for_a_backend), "max conn for a backend(default: 0)", NULL); + return 0; } @@ -349,6 +353,14 @@ int main_cmdline(int argc, char **argv) { } srv->wait_timeout = frontend->wait_timeout; + if (frontend->max_conn_for_a_backend <= 0) { + g_critical("--max_conn_for_a_backend is %d, which means there is not any conn limitation for a backend", frontend->max_conn_for_a_backend); + } else { + g_message("--max_conn_for_a_backend is %d ", frontend->max_conn_for_a_backend); + } + + srv->max_conn_for_a_backend = frontend->max_conn_for_a_backend; + /* assign the mysqld part to the */ network_mysqld_init(srv, frontend->default_file); /* starts the also the lua-scope, LUA_PATH and LUA_CPATH have to be set before this being called */ diff --git a/src/network-backend.h b/src/network-backend.h index 85ce855..d5ebde2 100644 --- a/src/network-backend.h +++ b/src/network-backend.h @@ -59,7 +59,7 @@ typedef struct { // network_connection_pool *pool; /**< the pool of open connections */ GPtrArray *pools; - guint connected_clients; /**< number of open connections to this backend for SQF */ + gint connected_clients; /**< number of open connections to this backend for SQF */ GString *uuid; /**< the UUID of the backend */ diff --git a/src/network-conn-pool-lua.c b/src/network-conn-pool-lua.c index dae6e29..ac56935 100644 --- a/src/network-conn-pool-lua.c +++ b/src/network-conn-pool-lua.c @@ -125,7 +125,12 @@ int network_connection_pool_lua_add_connection(network_mysqld_con *con) { event_set(&(con->server->event), con->server->fd, EV_READ, network_mysqld_con_idle_handle, pool_entry); chassis_event_add_local(con->srv, &(con->server->event)); /* add a event, but stay in the same thread */ } - + + if (!g_atomic_int_compare_and_exchange(&st->backend->connected_clients, 0, 0)) { + g_atomic_int_dec_and_test(&st->backend->connected_clients); + //g_critical("add_connection: %08x's connected_clients is %d\n", backend, backend->connected_clients); + } + // st->backend->connected_clients--; st->backend = NULL; st->backend_ndx = -1; @@ -136,7 +141,16 @@ int network_connection_pool_lua_add_connection(network_mysqld_con *con) { } network_socket *self_connect(network_mysqld_con *con, network_backend_t *backend, GHashTable *pwd_table) { - //1. connect DB + + /*make sure that the max conn for the backend is no more than the config number + *when max_conn_for_a_backend is no more than 0, there is no limitation for max connection for a backend; + * */ + if (con->srv->max_conn_for_a_backend > 0 && backend->connected_clients >= con->srv->max_conn_for_a_backend) { + g_critical("%s.%d: self_connect:%08x's connected_clients is %d, which are too many!",__FILE__, __LINE__, backend, backend->connected_clients); + return NULL; + } + + //1. connect DB network_socket *sock = network_socket_new(); network_address_copy(sock->dst, backend->addr); if (-1 == (sock->fd = socket(sock->dst->addr.common.sa_family, sock->socket_type, 0))) { @@ -267,7 +281,7 @@ network_socket *self_connect(network_mysqld_con *con, network_backend_t *backend sock->challenge = challenge; sock->response = network_mysqld_auth_response_copy(con->client->response); - + g_atomic_int_inc(&backend->connected_clients); return sock; } @@ -304,11 +318,13 @@ network_socket *network_connection_pool_lua_swap(network_mysqld_con *con, int ba #ifdef DEBUG_CONN_POOL g_debug("%s: (swap) check if we have a connection for this user in the pool '%s'", G_STRLOC, con->client->response ? con->client->response->username->str: "empty_user"); #endif + int flag = 0; network_connection_pool* pool = chassis_event_thread_pool(backend); if (NULL == (send_sock = network_connection_pool_get(pool))) { /** * no connections in the pool */ + flag = 1; if (NULL == (send_sock = self_connect(con, backend, pwd_table))) { st->backend_ndx = -1; return NULL; @@ -325,6 +341,11 @@ network_socket *network_connection_pool_lua_swap(network_mysqld_con *con, int ba st->backend = backend; // st->backend->connected_clients++; st->backend_ndx = backend_ndx; + + if (flag == 0 && !g_atomic_int_compare_and_exchange(&st->backend->connected_clients, 0, 0)) { + g_atomic_int_dec_and_test(&st->backend->connected_clients); + //g_critical("pool_lua_swap:%08x's connected_clients is %d\n", backend, backend->connected_clients); + } return send_sock; } diff --git a/src/network-mysqld.c b/src/network-mysqld.c index 82238ee..0d1ad6d 100644 --- a/src/network-mysqld.c +++ b/src/network-mysqld.c @@ -204,6 +204,14 @@ void network_mysqld_con_free(network_mysqld_con *con) { if (con->server) network_socket_free(con->server); if (con->client) network_socket_free(con->client); + + network_mysqld_con_lua_t *st = con->plugin_con_state; + if (st && st->backend) { + if (!g_atomic_int_compare_and_exchange(&st->backend->connected_clients, 0, 0)) { + g_atomic_int_dec_and_test(&st->backend->connected_clients); + //g_critical("last in CON_STATE_CONNECT_SERVER: %08x's connected_clients is %d\n", st->onnected_clients); + } + } /* we are still in the conns-array */ /* @@ -982,7 +990,10 @@ void network_mysqld_con_handle(int event_fd, short events, void *user_data) { network_socket_free(con->server); con->server = NULL; ostate = CON_STATE_INIT; - + if (!g_atomic_int_compare_and_exchange(&st->backend->connected_clients, 0, 0)) { + g_atomic_int_dec_and_test(&st->backend->connected_clients); + //g_critical("last in CON_STATE_CONNECT_SERVER: %08x's connected_clients is %d\n", st->onnected_clients); + } g_warning("timeout in connecting server"); break; } @@ -1120,6 +1131,10 @@ void network_mysqld_con_handle(int event_fd, short events, void *user_data) { break; case CON_STATE_READ_AUTH: { /* read auth from client */ + if (events == EV_TIMEOUT) { + con->state = CON_STATE_ERROR; + break; + } network_socket *recv_sock; recv_sock = con->client; @@ -1130,7 +1145,7 @@ void network_mysqld_con_handle(int event_fd, short events, void *user_data) { case NETWORK_SOCKET_SUCCESS: break; case NETWORK_SOCKET_WAIT_FOR_EVENT: - WAIT_FOR_EVENT(con->client, EV_READ, 0); + WAIT_FOR_EVENT(con->client, EV_READ, srv->wait_timeout); NETWORK_MYSQLD_CON_TRACK_TIME(con, "wait_for_event::read_auth"); return;