sql >> Base de Datos >  >> RDS >> Mysql

Manejo y limitación de conexiones con ProxySQL

La capacidad de dar forma al tráfico que va a la base de datos es una de las más importantes. En los últimos días, no tenía mucho control sobre él:las aplicaciones enviaban el tráfico a la base de datos y eso es todo. HAProxy, que se usaba comúnmente, tampoco tiene una opción para un control detallado sobre el tráfico. Con la introducción de proxies compatibles con SQL, como ProxySQL, los administradores de bases de datos dispusieron de más posibilidades. Echemos un vistazo a las posibilidades de manejo y limitación de conexiones en ProxySQL.

Manejo de conexiones en ProxySQL

Como sabrá, la forma en que funciona ProxySQL es a través de las reglas de consulta. Es una lista de reglas contra las que se prueba cada consulta y que rigen exactamente cómo ProxySQL manejará la consulta. Comenzando desde el principio, la aplicación se conecta a ProxySQL. Se autenticará contra ProxySQL (es por eso que ProxySQL tiene que almacenar todos los hashes de usuarios y contraseñas) y luego ProxySQL lo ejecutará a través de las reglas de consulta para determinar a qué grupo de host se debe enviar la consulta.

ProxySQL abre un grupo de conexiones a los servidores back-end. No es un mapeo 1 a 1, por defecto intenta reutilizar una conexión backend para tantas conexiones frontend como sea posible. Esto se denomina multiplexación de conexión. Los detalles dependen del tráfico exacto que tiene que manejar. Cada transacción abierta tiene que ser manejada dentro de la misma conexión. Si hay algún tipo de variable local definida, esta conexión no se puede reutilizar. Ser capaz de reutilizar una única conexión de back-end por múltiples conexiones de front-end reduce significativamente la carga en la base de datos de back-end.

Una vez realizada la conexión al ProxySQL, como mencionamos anteriormente, se procesará de acuerdo a las reglas de consulta. Aquí puede tener lugar la conformación del tráfico. Echemos un vistazo a las opciones

Aceleración de conexión en ProxySQL

Primero, eliminemos todos los SELECT. Estamos ejecutando nuestra "aplicación", Sysbench, de la siguiente manera:

[email protected]:~# sysbench /root/sysbench/src/lua/oltp_read_only.lua --threads=4 --events=200 --time=0 --mysql-host=10.0.0.101 --mysql-user=sbtest --mysql-password=sbtest --mysql-port=6033 --tables=32 --report-interval=1 --skip-trx=on --table-size=100000 --db-ps-mode=disable --rate=10 run

sysbench 1.1.0-bbee5d5 (using bundled LuaJIT 2.1.0-beta3)



Running the test with following options:

Number of threads: 4

Target transaction rate: 10/sec

Report intermediate results every 1 second(s)

Initializing random number generator from current time




Initializing worker threads...



Threads started!



[ 1s ] thds: 4 tps: 5.97 qps: 103.49 (r/w/o: 103.49/0.00/0.00) lat (ms,95%): 244.38 err/s: 0.00 reconn/s: 0.00

[ 1s ] queue length: 0, concurrency: 4

[ 2s ] thds: 4 tps: 13.02 qps: 181.32 (r/w/o: 181.32/0.00/0.00) lat (ms,95%): 580.02 err/s: 0.00 reconn/s: 0.00

[ 2s ] queue length: 5, concurrency: 4

[ 3s ] thds: 4 tps: 14.99 qps: 228.81 (r/w/o: 228.81/0.00/0.00) lat (ms,95%): 669.89 err/s: 0.00 reconn/s: 0.00

[ 3s ] queue length: 1, concurrency: 4

[ 4s ] thds: 4 tps: 16.99 qps: 232.88 (r/w/o: 232.88/0.00/0.00) lat (ms,95%): 350.33 err/s: 0.00 reconn/s: 0.00

[ 4s ] queue length: 0, concurrency: 3

[ 5s ] thds: 4 tps: 8.99 qps: 99.91 (r/w/o: 99.91/0.00/0.00) lat (ms,95%): 369.77 err/s: 0.00 reconn/s: 0.00

[ 5s ] queue length: 0, concurrency: 1

[ 6s ] thds: 4 tps: 3.99 qps: 55.81 (r/w/o: 55.81/0.00/0.00) lat (ms,95%): 147.61 err/s: 0.00 reconn/s: 0.00

[ 6s ] queue length: 0, concurrency: 1

[ 7s ] thds: 4 tps: 11.06 qps: 162.89 (r/w/o: 162.89/0.00/0.00) lat (ms,95%): 173.58 err/s: 0.00 reconn/s: 0.00

[ 7s ] queue length: 0, concurrency: 2

[ 8s ] thds: 4 tps: 7.99 qps: 112.88 (r/w/o: 112.88/0.00/0.00) lat (ms,95%): 200.47 err/s: 0.00 reconn/s: 0.00

[ 8s ] queue length: 0, concurrency: 2

[ 9s ] thds: 4 tps: 9.01 qps: 110.09 (r/w/o: 110.09/0.00/0.00) lat (ms,95%): 71.83 err/s: 0.00 reconn/s: 0.00

[ 9s ] queue length: 0, concurrency: 0

[ 10s ] thds: 4 tps: 9.99 qps: 143.87 (r/w/o: 143.87/0.00/0.00) lat (ms,95%): 153.02 err/s: 0.00 reconn/s: 0.00

[ 10s ] queue length: 0, concurrency: 1

[ 11s ] thds: 4 tps: 12.02 qps: 177.28 (r/w/o: 177.28/0.00/0.00) lat (ms,95%): 170.48 err/s: 0.00 reconn/s: 0.00

[ 11s ] queue length: 0, concurrency: 1

[ 12s ] thds: 4 tps: 5.00 qps: 70.95 (r/w/o: 70.95/0.00/0.00) lat (ms,95%): 231.53 err/s: 0.00 reconn/s: 0.00

[ 12s ] queue length: 0, concurrency: 2

[ 13s ] thds: 4 tps: 10.00 qps: 137.01 (r/w/o: 137.01/0.00/0.00) lat (ms,95%): 223.34 err/s: 0.00 reconn/s: 0.00

[ 13s ] queue length: 0, concurrency: 1

[ 14s ] thds: 4 tps: 11.01 qps: 143.14 (r/w/o: 143.14/0.00/0.00) lat (ms,95%): 130.13 err/s: 0.00 reconn/s: 0.00

[ 14s ] queue length: 0, concurrency: 0

[ 15s ] thds: 4 tps: 5.00 qps: 100.99 (r/w/o: 100.99/0.00/0.00) lat (ms,95%): 297.92 err/s: 0.00 reconn/s: 0.00

[ 15s ] queue length: 0, concurrency: 4

[ 16s ] thds: 4 tps: 10.98 qps: 122.82 (r/w/o: 122.82/0.00/0.00) lat (ms,95%): 344.08 err/s: 0.00 reconn/s: 0.00

[ 16s ] queue length: 0, concurrency: 0

[ 17s ] thds: 4 tps: 3.00 qps: 59.01 (r/w/o: 59.01/0.00/0.00) lat (ms,95%): 287.38 err/s: 0.00 reconn/s: 0.00

[ 17s ] queue length: 0, concurrency: 2

[ 18s ] thds: 4 tps: 13.01 qps: 165.14 (r/w/o: 165.14/0.00/0.00) lat (ms,95%): 173.58 err/s: 0.00 reconn/s: 0.00

[ 18s ] queue length: 0, concurrency: 0

[ 19s ] thds: 4 tps: 6.99 qps: 98.79 (r/w/o: 98.79/0.00/0.00) lat (ms,95%): 253.35 err/s: 0.00 reconn/s: 0.00

[ 19s ] queue length: 0, concurrency: 1

[ 20s ] thds: 4 tps: 9.98 qps: 164.60 (r/w/o: 164.60/0.00/0.00) lat (ms,95%): 590.56 err/s: 0.00 reconn/s: 0.00

[ 20s ] queue length: 0, concurrency: 3

SQL statistics:

    queries performed:

        read:                            2800

        write:                           0

        other:                           0

        total:                           2800

    transactions:                        200    (9.64 per sec.)

    queries:                             2800   (134.89 per sec.)

    ignored errors:                      0      (0.00 per sec.)

    reconnects:                          0      (0.00 per sec.)



Throughput:

    events/s (eps):                      9.6352

    time elapsed:                        20.7573s

    total number of events:              200



Latency (ms):

         min:                                   44.36

         avg:                                  202.66

         max:                                  726.59

         95th percentile:                      590.56

         sum:                                40531.73



Threads fairness:

    events (avg/stddev):           50.0000/0.71

    execution time (avg/stddev):   10.1329/0.05

Es un tráfico completamente de solo lectura, debe promediar 10 transacciones (140 consultas) por segundo. Como solo son SELECT, podemos modificar fácilmente una de las reglas de consulta existentes y bloquear el tráfico:

Esto dará como resultado el siguiente error en el lado de la aplicación:

[email protected]:~# sysbench /root/sysbench/src/lua/oltp_read_only.lua --threads=4 --events=200 --time=0 --mysql-host=10.0.0.101 --mysql-user=sbtest --mysql-password=sbtest --mysql-port=6033 --tables=32 --report-interval=1 --skip-trx=on --table-size=100000 --db-ps-mode=disable --rate=10 run

sysbench 1.1.0-bbee5d5 (using bundled LuaJIT 2.1.0-beta3)



Running the test with following options:

Number of threads: 4

Target transaction rate: 10/sec

Report intermediate results every 1 second(s)

Initializing random number generator from current time




Initializing worker threads...



Threads started!



FATAL: mysql_drv_query() returned error 1148 (SELECT queries are not allowed!!!) for query 'SELECT c FROM sbtest25 WHERE id=83384'

FATAL: `thread_run' function failed: /usr/local/share/sysbench/oltp_common.lua:426: SQL error, errno = 1148, state = '42000': SELECT queries are not allowed!!!

Ahora, esto es obviamente duro. Podemos ser más educados y simplemente aumentar la demora para las consultas SELECT.

Esto, obviamente, afecta el rendimiento de las consultas ya que se agregan 10 milisegundos a cada SELECT que se ejecuta.

SQL statistics:

    queries performed:

        read:                            2800

        write:                           0

        other:                           0

        total:                           2800

    transactions:                        200    (5.60 per sec.)

    queries:                             2800   (78.44 per sec.)

    ignored errors:                      0      (0.00 per sec.)

    reconnects:                          0      (0.00 per sec.)



Throughput:

    events/s (eps):                      5.6030

    time elapsed:                        35.6952s

    total number of events:              200



Latency (ms):

         min:                                  622.04

         avg:                                 7957.01

         max:                                18808.60

         95th percentile:                    15934.78

         sum:                              1591401.12



Threads fairness:

    events (avg/stddev):           50.0000/36.01

    execution time (avg/stddev):   397.8503/271.50

Configuramos retrasos para cada consulta SELECT, lo que no tiene necesariamente ningún sentido más que demostrar que puede hacerlo. Por lo general, le gustaría usar el retraso en algunas consultas infractoras. Digamos que tenemos una consulta que es muy pesada y agrega una carga significativa en la CPU de la base de datos. Lo que es peor, ha sido introducido por un cambio de código reciente y proviene de todos los hosts de aplicaciones. Claro, puede esperar a que los desarrolladores reviertan el cambio o apliquen una solución, pero con ProxySQL puede tomar el control en sus propias manos y simplemente bloquear la consulta o reducir su impacto de manera significativa.

Supongamos que nuestra base de datos se está moviendo bien cuando las campanas de alarma comienzan a sonar.

Una mirada rápida a las métricas nos dice que la cantidad de consultas ejecutadas por ProxySQL se cae mientras que la utilización de la CPU aumenta. Podemos mirar las consultas principales en ProxySQL para ver si podemos notar algo inusual.

De hecho, es inusual:una nueva consulta que no forma parte de la combinación de consultas regulares que observamos en nuestro sistema. Podemos usar la opción para crear la regla de consulta.

Agregaremos un retraso de 50 segundos a la consulta configurando Delay en 50000 Sra.

Podemos confirmar que la regla de consulta está en uso y las consultas la están alcanzando .

Después de un momento también podemos notar que la carga cae y el número de consultas ejecutadas está nuevamente en el rango esperado. Por supuesto, en lugar de agregar el retraso a la consulta, simplemente podríamos bloquearla. Eso habría sido aún más fácil de lograr para nosotros, pero el bloqueo total de la consulta puede tener un impacto significativo en la aplicación.

Esperamos que esta breve publicación de blog le brinde una idea de cómo ProxySQL puede ayudarlo a dar forma a su tráfico y reducir el impacto en el rendimiento que presentan las consultas fuera de control.