diff --git a/doc.ja/src/sgml/loadbalance.sgml b/doc.ja/src/sgml/loadbalance.sgml index 950cdb0..115081a 100644 --- a/doc.ja/src/sgml/loadbalance.sgml +++ b/doc.ja/src/sgml/loadbalance.sgml @@ -857,14 +857,19 @@ black_query_pattern_list = 'SELECT \* FROM table_name1\;;SELECT col1, col2 FROM Specifies the list of "database-name:node id" pairs to send SELECT queries to a particular backend node for a particular database connection. +--> +特定のデータベース接続でSELECTクエリが指定したロードバランス比率で特定のバックエンドノードに送信されるように、"データベース名:ノードID(比率)"ペアのリストを指定します。ロードバランス比率は0-1の間の値を指定します。 +比率の指定を省略した場合は、デフォルトの1.0となります。 + + + -特定のデータベース接続ではSELECTクエリが特定のバックエンドノードに送信されるように、"データベース名:ノードID"ペアのリストを指定します。 -たとえば"test:1"とした場合、"test"データベースへの接続においては、Pgpool-IIは全てのSELECTクエリをIDが1のバックエンドノードに送信します。 +たとえば"test:1(0.5)"とした場合、"test"データベースへの接続においては、Pgpool-IIは50%のSELECTクエリをIDが1のバックエンドノードに送信します。 複数の"データベース名:ノードID"のペアを カンマ(,)で区切って指定することができます。 @@ -875,10 +880,10 @@ black_query_pattern_list = 'SELECT \* FROM table_name1\;;SELECT col1, col2 FROM if "standby" is specified, one of the standby nodes are selected randomly based on weights. --> -データベース名には正規表現を指定することできます。 +データベース名には正規表現を指定することができます。 ノードIDには特別なキーワードを使うことができます。 "primary"が指定された場合にはクエリはプライマリノードに送られます。 -また、"standby"が指定された場合はスタンバイノードのうちどれかをウェイトに応じてランダムに選択します。 +また、"standby"が指定された場合はスタンバイノードのうちどれかをウェイト()に応じてランダムに選択します。 @@ -909,7 +914,7 @@ black_query_pattern_list = 'SELECT \* FROM table_name1\;;SELECT col1, col2 FROM Route all SELECT queries on mydb0 or on mydb1 databases to backend node of ID 1. --> -全てのmydb0またはmydb1データベースにおけるSELECTクエリはIDが1のバックエンドノードに送る。 +全てのmydb0またはmydb1データベースにおける30%のSELECTクエリはIDが1のバックエンドノードに送る。 @@ -929,7 +934,7 @@ black_query_pattern_list = 'SELECT \* FROM table_name1\;;SELECT col1, col2 FROM --> は以下のように設定します。 -database_redirect_preference_list = 'postgres:primary,mydb[01]:1,mydb2:standby' +database_redirect_preference_list = 'postgres:primary,mydb[01]:1(0.3),mydb2:standby' @@ -960,7 +965,7 @@ database_redirect_preference_list = 'postgres:primary,mydb[01]:1,mydb2:standby' to send SELECT queries to a particular backend node for a particular client application connection. --> -特定のクライアントアプリケーションの接続ではSELECTクエリが特定のバックエンドノードに送信されるように、"アプリケーション名:ノードID"ペアのリストを指定します。 +特定のクライアントアプリケーションの接続でSELECTクエリが指定したロードバランス比率で特定のバックエンドノードに送信されるように、"アプリケーション名:ノードID(比率)"ペアのリストを指定します。 @@ -1005,6 +1010,7 @@ database_redirect_preference_list = 'postgres:primary,mydb[01]:1,mydb2:standby' --> の記法はと同じですので、アプリケーション名には正規表現も使用できます。 同様に特別なキーワード"primary"はプライマリノードを、"standby"はスタンバイサーバのいずれかを意味します。 +ロードバランス比率は0-1の間の値を指定します。ロードバランス比率の指定を省略した場合は、デフォルトの1.0となります。 @@ -1035,7 +1041,7 @@ database_redirect_preference_list = 'postgres:primary,mydb[01]:1,mydb2:standby' Route all SELECT queries from myapp1 client to backend node of ID 1. --> -全てのmyapp1クライアントからのSELECTクエリはIDが1のバックエンドノードに送る。 +全てのmyapp1クライアントからの30%のSELECTクエリはIDが1のバックエンドノードに送る。 @@ -1055,7 +1061,7 @@ database_redirect_preference_list = 'postgres:primary,mydb[01]:1,mydb2:standby' --> は以下のように設定します。 -app_name_redirect_preference_list = 'psql:primary,myapp1:1,myapp2:standby' +app_name_redirect_preference_list = 'psql:primary,myapp1:1(0.3),myapp2:standby' @@ -1068,6 +1074,39 @@ app_name_redirect_preference_list = 'psql:primary,myapp1:1,myapp2:standby' --> は、よりも優先されます。 + + +たとえば、 +database_redirect_preference_list = 'postgres:standby(1.0)'、 +app_name_redirect_preference_list = 'myapp1:primary(1.0)' +と設定した場合、アプリケーションmyapp1postgresデータベースでのSELECTはプライマリバックエンドノードに送られます。 + + + + + + +及びの設定では、複数のデータベース名やアプリケーション名にマッチした場合、最初の設定が反映されます。 + + + +たとえば、 +database_redirect_preference_list = 'postgres:primary,postgres:standby' +と設定した場合、postgres:primaryの設定が反映されます。 + @@ -1081,7 +1120,7 @@ app_name_redirect_preference_list = 'psql:primary,myapp1:1,myapp2:standby' If you want to use the feature through JDBC, use postgreSQL-9.4 or later version of the driver. --> -JDBCドライバのpostgresql-9.3以前のバージョンでは、JDBCドライバの"ApplicationName" と "assumeMinServerVersion=9.0"オプションを指定してもスタートアップパケットの中にアプリケーション名を含ません。 +JDBCドライバのpostgresql-9.3以前のバージョンでは、JDBCドライバの"ApplicationName" と "assumeMinServerVersion=9.0"オプションを指定してもスタートアップパケットの中にアプリケーション名を含みません。 JDBCから機能を使用したければ、postgresql-9.4 以降のドライバをお使いください diff --git a/doc/src/sgml/loadbalance.sgml b/doc/src/sgml/loadbalance.sgml index 90a7cb3..0a9d3b5 100644 --- a/doc/src/sgml/loadbalance.sgml +++ b/doc/src/sgml/loadbalance.sgml @@ -656,11 +656,14 @@ black_query_pattern_list = 'SELECT \* FROM table_name1\;;SELECT col1, col2 FROM - Specifies the list of "database-name:node id" pairs + Specifies the list of "database-name:node id(ratio)" pairs to send SELECT queries to a particular backend - node for a particular database connection. - For example, by specifying "test:1", Pgpool-II - will redirect all SELECT queries to the backend node of ID 1 for + node for a particular database connection at a specified load balance ratio. + The load balance ratio specifies a value between 0 and 1. The default is 1.0. + + + For example, by specifying "test:1(0.5)", Pgpool-II + will redirect 50% SELECT queries to the backend node of ID 1 for the connection to "test" database. You can specify multiple "database name:node id" pair by separating them using comma (,). @@ -670,7 +673,7 @@ black_query_pattern_list = 'SELECT \* FROM table_name1\;;SELECT col1, col2 FROM You can use special keywords as node id. If "primary" is specified, queries are sent to the primary node, and if "standby" is specified, one of the standby nodes are selected randomly - based on weights. + based on weights (). @@ -688,8 +691,9 @@ black_query_pattern_list = 'SELECT \* FROM table_name1\;;SELECT col1, col2 FROM - Route all SELECT queries on mydb0 or on - mydb1 databases to backend node of ID 1. + Route 30% SELECT queries on mydb0 or on + mydb1 databases to backend node of ID. + The other 70% SELECT queries will be sent to other backend nodes. @@ -703,7 +707,7 @@ black_query_pattern_list = 'SELECT \* FROM table_name1\;;SELECT col1, col2 FROM then the will be configured as follows: -database_redirect_preference_list = 'postgres:primary,mydb[01]:1,mydb2:standby' +database_redirect_preference_list = 'postgres:primary,mydb[01]:1(0.3),mydb2:standby' @@ -723,9 +727,9 @@ database_redirect_preference_list = 'postgres:primary,mydb[01]:1,mydb2:standby' - Specifies the list of "application-name:node id" pairs + Specifies the list of "application-name:node id(ratio)" pairs to send SELECT queries to a particular backend - node for a particular client application connection. + node for a particular client application connection at a specified load balance ratio. @@ -737,7 +741,7 @@ database_redirect_preference_list = 'postgres:primary,mydb[01]:1,mydb2:standby' For example, application name of psql command is - "psql" + "psql". @@ -756,6 +760,7 @@ database_redirect_preference_list = 'postgres:primary,mydb[01]:1,mydb2:standby' thus you can also use the regular expressions for application names. Similarly special keyword "primary" indicates the primary node and "standby" indicates one of standby nodes. + The load balance weight specifies a value between 0 and 1. The default is 1.0. @@ -773,8 +778,8 @@ database_redirect_preference_list = 'postgres:primary,mydb[01]:1,mydb2:standby' - Route all SELECT queries from myapp1 - client to backend node of ID 1. + Route 30% SELECT queries from myapp1 + client to backend node of ID 1. The other 70% SELECT queries will be sent to other backend nodes. @@ -788,7 +793,7 @@ database_redirect_preference_list = 'postgres:primary,mydb[01]:1,mydb2:standby' then the will be configured as follows: -app_name_redirect_preference_list = 'psql:primary,myapp1:1,myapp2:standby' +app_name_redirect_preference_list = 'psql:primary,myapp1:1(0.3),myapp2:standby' @@ -798,6 +803,25 @@ app_name_redirect_preference_list = 'psql:primary,myapp1:1,myapp2:standby' takes precedence over the . + + For example, if you set + database_redirect_preference_list = 'postgres:standby(1.0)' and + app_name_redirect_preference_list = 'myapp1:primary(1.0)', + all SELECT from application myapp1 on postgres database will be sent to primary backend node. + + + + + + By specifying of and + , when multiple database + names and application names are matched, the first setting will be used. + + + For example, if you set + database_redirect_preference_list = 'postgres:primary,postgres:standby', + "postgres: primary" will be used. + diff --git a/src/include/utils/regex_array.h b/src/include/utils/regex_array.h index 48768aa..3596ca6 100644 --- a/src/include/utils/regex_array.h +++ b/src/include/utils/regex_array.h @@ -46,6 +46,7 @@ void destroy_regex_arrary(RegArray *ar); typedef struct { char *left_token; char *right_token; + double weight_token; } Left_right_token; typedef struct { diff --git a/src/protocol/child.c b/src/protocol/child.c index 4a970c5..b2669ee 100644 --- a/src/protocol/child.c +++ b/src/protocol/child.c @@ -1666,9 +1666,10 @@ int select_load_balancing_node(void) int selected_slot; double total_weight,r; int i; - int index; + int index_db = -1, index_app = -1; POOL_SESSION_CONTEXT *ses = pool_get_session_context(false); int tmp; + int no_load_balance_node_id = -2; /* * -2 indicates there's no database_redirect_preference_list. -1 indicates @@ -1677,7 +1678,13 @@ int select_load_balancing_node(void) */ int suggested_node_id = -2; - /* +#if defined(sun) || defined(__sun) + r = (((double)rand())/RAND_MAX); +#else + r = (((double)random())/RAND_MAX); +#endif + + /* * Check database_redirect_preference_list */ if (SL_MODE && pool_config->redirect_dbnames) @@ -1687,23 +1694,23 @@ int select_load_balancing_node(void) /* Check to see if the database matches any of * database_redirect_preference_list */ - index = regex_array_match(pool_config->redirect_dbnames, database); - if (index >= 0) + index_db = regex_array_match(pool_config->redirect_dbnames, database); + if (index_db >= 0) { /* Matches */ ereport(DEBUG1, (errmsg("selecting load balance node db matched"), - errdetail("dbname: %s index is %d dbnode is %s", database, index, pool_config->db_redirect_tokens->token[index].right_token))); + errdetail("dbname: %s index is %d dbnode is %s weight is %f", database, index_db, + pool_config->db_redirect_tokens->token[index_db].right_token, + pool_config->db_redirect_tokens->token[index_db].weight_token))); - tmp = choose_db_node_id(pool_config->db_redirect_tokens->token[index].right_token); + tmp = choose_db_node_id(pool_config->db_redirect_tokens->token[index_db].right_token); if (tmp == -1 || (tmp >= 0 && VALID_BACKEND(tmp))) - { suggested_node_id = tmp; - } } } - /* + /* * Check app_name_redirect_preference_list */ if (SL_MODE && pool_config->redirect_app_names) @@ -1716,33 +1723,64 @@ int select_load_balancing_node(void) */ if (app_name && strlen(app_name) > 0) { - /* Check to see if the aplication name matches any of + /* + * Check to see if the aplication name matches any of * app_name_redirect_preference_list. */ - index = regex_array_match(pool_config->redirect_app_names, app_name); - if (index >= 0) + index_app = regex_array_match(pool_config->redirect_app_names, app_name); + if (index_app >= 0) { + + /* + * if the aplication name matches any of app_name_redirect_preference_list, + * database_redirect_preference_list will be ignored. + */ + index_db = -1; + /* Matches */ ereport(DEBUG1, (errmsg("selecting load balance node db matched"), - errdetail("app_name: %s index is %d dbnode is %s", app_name, index, pool_config->app_name_redirect_tokens->token[index].right_token))); + errdetail("app_name: %s index is %d dbnode is %s weight is %f", app_name, index_app, + pool_config->app_name_redirect_tokens->token[index_app].right_token, + pool_config->app_name_redirect_tokens->token[index_app].weight_token))); - tmp = choose_db_node_id(pool_config->app_name_redirect_tokens->token[index].right_token); + tmp = choose_db_node_id(pool_config->app_name_redirect_tokens->token[index_app].right_token); if (tmp == -1 || (tmp >= 0 && VALID_BACKEND(tmp))) - { suggested_node_id = tmp; - } } } } if (suggested_node_id >= 0) { - ereport(DEBUG1, - (errmsg("selecting load balance node"), - errdetail("selected backend id is %d", suggested_node_id))); + /* + * If the weight is bigger than random rate then send to suggested_node_id. + * If the weight is less than random rate then choose load balance node from other nodes. + */ + if ((index_db >= 0 && r <= pool_config->db_redirect_tokens->token[index_db].weight_token) || + (index_app >= 0 && r <= pool_config->app_name_redirect_tokens->token[index_app].weight_token)) + { + ereport(DEBUG1, + (errmsg("selecting load balance node"), + errdetail("selected backend id is %d", suggested_node_id))); + return suggested_node_id; + } + else + no_load_balance_node_id = suggested_node_id; + } - return suggested_node_id; + /* In case of sending to standby */ + if (suggested_node_id == -1) + { + /* If the weight is less than random rate then send to primary. */ + if ((index_db >= 0 && r > pool_config->db_redirect_tokens->token[index_db].weight_token) || + (index_app >= 0 && r > pool_config->app_name_redirect_tokens->token[index_app].weight_token)) + { + ereport(DEBUG1, + (errmsg("selecting load balance node"), + errdetail("selected backend id is %d", PRIMARY_NODE_ID))); + return PRIMARY_NODE_ID; + } } /* Choose a backend in random manner with weight */ @@ -1753,6 +1791,8 @@ int select_load_balancing_node(void) { if (VALID_BACKEND(i)) { + if (i == no_load_balance_node_id) + continue; if (suggested_node_id == -1) { if (i != PRIMARY_NODE_ID) @@ -1772,7 +1812,7 @@ int select_load_balancing_node(void) total_weight = 0.0; for (i=0;i 0.0) diff --git a/src/test/regression/tests/008.dbredirect/test.sh b/src/test/regression/tests/008.dbredirect/test.sh index 64bfafb..8d1af9b 100755 --- a/src/test/regression/tests/008.dbredirect/test.sh +++ b/src/test/regression/tests/008.dbredirect/test.sh @@ -25,7 +25,7 @@ echo "done." source ./bashrc.ports -echo "database_redirect_preference_list = 'postgres:primary,test:1,mydb[5-9]:2,test2:standby'" >> etc/pgpool.conf +echo "database_redirect_preference_list = 'postgres:primary,test:1,mydb[5-9]:2,test2:standby,test3:primary(0.0),test4:standby(0.0),test5:primary(1.0)'" >> etc/pgpool.conf ./startall @@ -34,6 +34,9 @@ wait_for_pgpool_startup $CREATEDB mydb6 $CREATEDB test2 +$CREATEDB test3 +$CREATEDB test4 +$CREATEDB test5 $PGBENCH -i postgres ok=yes @@ -41,22 +44,45 @@ ok=yes # should be redirect to primary (node 0) $PSQL -c "SELECT 'test1'" postgres -test `getnode "test1"` -eq 0 || ok=ng +test `getnode "'test1'"` -eq 0 || ok=ng +echo $ok # should be redirect to node 1 $PSQL -c "SELECT 'test2'" test -test `getnode "test2"` -eq 1 || ok=ng +test `getnode "'test2'"` -eq 1 || ok=ng +echo $ok # should be redirect to node 2 $PSQL -c "SELECT 'test3'" mydb6 -test `getnode "test3"` -eq 2 || ok=ng +test `getnode "'test3'"` -eq 2 || ok=ng +echo $ok # should be redirect to either node 1 or 2 $PSQL -c "SELECT 'test4'" test2 -test `getnode "test4"` -eq 1 -o `getnode "test4"` -eq 2 || ok=ng +test `getnode "'test4'"` -eq 1 -o `getnode "test4"` -eq 2 || ok=ng +echo $ok + +# should be redirect to either node 1 or 2 +$PSQL -c "SELECT 'test5'" test3 + +test `getnode "'test5'"` -eq 1 -o `getnode "test5"` -eq 2 || ok=ng +echo $ok + +# should be redirect to primary (node 0) +$PSQL -c "SELECT 'test6'" test4 + +test `getnode "'test6'"` -eq 0 || ok=ng +echo $ok + +# should be redirect to primary (node 0) +$PSQL -c "SELECT 'test7'" test5 + +test `getnode "'test7'"` -eq 0 || ok=ng + +echo $ok echo "app_name_redirect_preference_list = 'psql:primary,pgbench:standby'" >> etc/pgpool.conf @@ -66,14 +92,36 @@ sleep 1 wait_for_pgpool_startup # should be redirect to node 0 because application name is psql -$PSQL -c "SELECT 'test5'" mydb6 +$PSQL -c "SELECT 'test8'" mydb6 -test `getnode "test5"` -eq 0 || ok=ng +test `getnode "'test8'"` -eq 0 || ok=ng +echo $ok # should be redirect to either node 1 or 2 $PGBENCH -t 1 -f ../select.pgbench postgres -test `getnode "test6"` -eq 1 -o `getnode "test6"` -eq 2 || ok=ng +test `getnode "'test9'"` -eq 1 -o `getnode "test9"` -eq 2 || ok=ng +echo $ok + + +echo "app_name_redirect_preference_list = 'psql:primary(0.0),pgbench:standby(1.0)'" >> etc/pgpool.conf + +./pgpool_reload +sleep 1 + +wait_for_pgpool_startup + +# should be redirect to either node 1 or 2 +$PSQL -c "SELECT 'test10'" mydb6 + +test `getnode "'test10'"` -eq 1 -o `getnode "test10"` -eq 2 || ok=ng +echo $ok + +# should be redirect to either node 1 or 2 +$PGBENCH -t 1 -f ../select.pgbench1 postgres + +test `getnode "'test11'"` -eq 1 -o `getnode "test11"` -eq 2 || ok=ng +echo $ok ./shutdownall diff --git a/src/utils/regex_array.c b/src/utils/regex_array.c index 5541d27..f85c168 100644 --- a/src/utils/regex_array.c +++ b/src/utils/regex_array.c @@ -193,11 +193,13 @@ void extract_string_tokens2(char *str, char *delimi, char delimi2, Left_right_to int len; char *left_token; char *right_token; + char *weight_token = NULL; int i,j; len = strlen(token)+1; left_token = palloc(len); right_token = palloc(len); + weight_token = palloc(len); for (i=0;token[i] && token[i] != delimi2;i++) left_token[i] = token[i]; @@ -216,11 +218,21 @@ void extract_string_tokens2(char *str, char *delimi, char delimi2, Left_right_to i++; j = 0; - for (;token[i];i++) + for (;token[i] && token[i] != '('; i++) right_token[j++] = token[i]; right_token[j] = '\0'; + /* delimiter 3 */ + int k = 0; + if (token[i] == '(') + { + i++; + for (;token[i] && token[i] != ')'; i++) + weight_token[k++] = token[i]; + } + weight_token[k] = '\0'; + if (lrtokens->pos == lrtokens->size) { lrtokens->size += AR_ALLOC_UNIT; @@ -228,6 +240,11 @@ void extract_string_tokens2(char *str, char *delimi, char delimi2, Left_right_to } lrtokens->token[lrtokens->pos].left_token = left_token; lrtokens->token[lrtokens->pos].right_token = right_token; + if (weight_token[0] != '\0') + lrtokens->token[lrtokens->pos].weight_token = atof(weight_token); + else + lrtokens->token[lrtokens->pos].weight_token = 1.0; + lrtokens->pos++; } pfree(mystr);