Pgbouncer cannot connect to server что делать
Перейти к содержимому

Pgbouncer cannot connect to server что делать

  • автор:

Common Error Messages

Caused when the the coordinator node is unable to connect to a worker.

SELECT 1 FROM companies WHERE id = 2928; 
ERROR: connection to the remote node localhost:5432 failed with the following error: could not connect to server: Connection refused Is the server running on host "localhost" (127.0.0.1) and accepting TCP/IP connections on port 5432?

Resolution

To fix, check that the worker is accepting connections, and that DNS is correctly resolving.

Canceling the transaction since it was involved in a distributed deadlock

Deadlocks can happen not only in a single-node database, but in a distributed database, caused by queries executing across multiple nodes. Citus has the intelligence to recognize distributed deadlocks and defuse them by aborting one of the queries involved.

We can see this in action by distributing rows across worker nodes, and then running two concurrent transactions with conflicting updates:

CREATE TABLE lockme (id int, x int); SELECT create_distributed_table('lockme', 'id'); -- goes to one worker, and another INSERT INTO lockme VALUES (1,1), (2,2); --------------- TX 1 ---------------- --------------- TX 2 ---------------- BEGIN; BEGIN; UPDATE lockme SET x = 3 WHERE id = 1; UPDATE lockme SET x = 4 WHERE id = 2; UPDATE lockme SET x = 3 WHERE id = 2; UPDATE lockme SET x = 4 WHERE id = 1; 
ERROR: canceling the transaction since it was involved in a distributed deadlock 

Resolution

Detecting deadlocks and stopping them is part of normal distributed transaction handling. It allows an application to retry queries or take another course of action.

Could not connect to server: Cannot assign requested address

WARNING: connection error: localhost:9703 DETAIL: could not connect to server: Cannot assign requested address 

This occurs when there are no more sockets available by which the coordinator can respond to worker requests.

Resolution

Configure the operating system to re-use TCP sockets. Execute this on the shell in the coordinator node:

sysctl -w net.ipv4.tcp_tw_reuse=1 

This allows reusing sockets in TIME_WAIT state for new connections when it is safe from a protocol viewpoint. Default value is 0 (disabled).

SSL error: certificate verify failed

As of Citus 8.1, nodes are required talk to one another using SSL by default. If SSL is not enabled on a Postgres server when Citus is first installed, the install process will enable it, which includes creating and self-signing an SSL certificate.

However, if a root certificate authority file exists (typically in ~/.postgresql/root.crt ), then the certificate will be checked unsuccessfully against that CA at connection time. The Postgres documentation about SSL support warns:

For backward compatibility with earlier versions of PostgreSQL, if a root CA file exists, the behavior of sslmode=require will be the same as that of verify-ca, meaning the server certificate is validated against the CA. Relying on this behavior is discouraged, and applications that need certificate validation should always use verify-ca or verify-full.

Resolution

Possible solutions are to sign the certificate, turn off SSL, or remove the root certificate. Also a node may have trouble connecting to itself without the help of citus.local_hostname (text) .

Could not connect to any active placements

When all available worker connection slots are in use, further connections will fail.

WARNING: connection error: hostname:5432 ERROR: could not connect to any active placements 

Resolution

This error happens most often when copying data into Citus in parallel. The COPY command opens up one connection per shard. If you run M concurrent copies into a destination with N shards, that will result in M*N connections. To solve the error, reduce the shard count of target distributed tables, or run fewer \copy commands in parallel.

Remaining connection slots are reserved for non-replication superuser connections

This occurs when PostgreSQL runs out of available connections to serve concurrent client requests.

Resolution

The max_connections GUC adjusts the limit, with a typical default of 100 connections. Note that each connection consumes resources, so adjust sensibly. When increasing max_connections it’s usually a good idea to increase memory limits too.

Using PgBouncer can also help by queueing connection requests which exceed the connection limit. Citus Cloud has a built-in PgBouncer instance, see Scaling Connections (pgBouncer) to learn how to connect through it.

PgBouncer cannot connect to server

In a self-hosted Citus cluster, this error indicates that the coordinator node is not responding to PgBouncer.

Resolution

Try connecting directly to the server with psql to ensure it is running and accepting connections.

Relation foo is not distributed

This error no longer occurs in the current version of Citus. It was caused by attempting to join local and distributed tables in the same query.

Resolution

Upgrade to Citus 10.0 or higher.

Unsupported clause type

This error no longer occurs in the current version of Citus. It used to happen when executing a join with an inequality condition:

SELECT * FROM identified_event ie JOIN field_calculator_watermark w ON ie.org_id = w.org_id WHERE w.org_id = 42 AND ie.version > w.version LIMIT 10; 
ERROR: unsupported clause type 

Resolution

Upgrade to Citus 7.2 or higher.

Cannot open new connections after the first modification command within a transaction

This error no longer occurs in the current version of Citus except in certain unusual shard repair scenarios. It used to happen when updating rows in a transaction, and then running another command which would open new coordinator-to-worker connections.

BEGIN; -- run modification command that uses one connection DELETE FROM http_request WHERE site_id = 8 AND ingest_time  now() - '1 week'::interval; -- now run a query that opens connections to more workers SELECT count(*) FROM http_request; 
ERROR: cannot open new connections after the first modification command within a transaction 

Resolution

Upgrade to Citus 7.2 or higher.

Cannot create uniqueness constraint

As a distributed system, Citus can guarantee uniqueness only if a unique index or primary key constraint includes a table’s distribution column. That is because the shards are split so that each shard contains non-overlapping partition column values. The index on each worker node can locally enforce its part of the constraint.

Trying to make a unique index on a non-distribution column will generate an error:

ERROR: creating unique indexes on non-partition columns is currently unsupported 

Enforcing uniqueness on a non-distribution column would require Citus to check every shard on every INSERT to validate, which defeats the goal of scalability.

Resolution

There are two ways to enforce uniqueness on a non-distribution column:

  1. Create a composite unique index or primary key that includes the desired column (C), but also includes the distribution column (D). This is not quite as strong a condition as uniqueness on C alone, but will ensure that the values of C are unique for each value of D. For instance if distributing by company_id in a multi-tenant system, this approach would make C unique within each company.
  2. Use a reference table rather than a hash distributed table. This is only suitable for small tables, since the contents of the reference table will be duplicated on all nodes.

Function create_distributed_table does not exist

SELECT create_distributed_table('foo', 'id'); /* ERROR: function create_distributed_table(unknown, unknown) does not exist LINE 1: SELECT create_distributed_table('foo', 'id'); HINT: No function matches the given name and argument types. You might need to add explicit type casts. */ 

Resolution

When basic Citus Utility Functions are not available, check whether the Citus extension is properly installed. Running \dx in psql will list installed extensions.

One way to end up without extensions is by creating a new database in a Postgres server, which requires extensions to be re-installed. See Creating a New Database to learn how to do it right.

STABLE functions used in UPDATE queries cannot be called with column references

Each PostgreSQL function is marked with a volatility, which indicates whether the function can update the database, and whether the function’s return value can vary over time given the same inputs. A STABLE function is guaranteed to return the same results given the same arguments for all rows within a single statement, while an IMMUTABLE function is guaranteed to return the same results given the same arguments forever.

Non-immutable functions can be inconvenient in distributed systems because they can introduce subtle changes when run at slightly different times across shard replicas. Differences in database configuration across nodes can also interact harmfully with non-immutable functions.

One of the most common ways this can happen is using the timestamp type in Postgres, which unlike timestamptz does not keep a record of time zone. Interpreting a timestamp column makes reference to the database timezone, which can be changed between queries, hence functions operating on timestamps are not immutable.

Citus forbids running distributed queries that filter results using stable functions on columns. For instance:

-- foo_timestamp is timestamp, not timestamptz UPDATE foo SET . WHERE foo_timestamp  now(); 
ERROR: STABLE functions used in UPDATE queries cannot be called with column references 

Resolution

Avoid stable functions on columns in a distributed UPDATE statement. In particular, whenever working with times use timestamptz rather than timestamp . Having a time zone in timestamptz makes calculations immutable.

© Copyright 2023, Citus Data, a Microsoft Company. Revision dcaa6e02 .

Как вынудить процесс использовать новый адрес DNS-сервера из обновлённого resolv.conf без перезапуска самого процесса

image

Я работаю системным администратором Unix. Однажды к нам в отдел эксплуатации сервисов упал тикет от программиста с выдержой из лога application-сервера в заголовке: «pgbouncer cannot connect to server«. Посмотрев логи pgbouncer’ов, я увидел, что периодически возникают lookup fail’ы при обращении к нашим DNS. Было установленно, что это связано не с работой наших DNS-серверов, а с ненадёжностью самого протокола UDP: иногда возникают потери пакетов по разным причинам.

В результате, было решено установить на каждом сервере с pgbouncer’ами по кэширующему BIND. И тут возникла интересная проблема: pgbouncer не перечитывал по сигналу HUP файл /etc/resolv.conf и продолжал обращаться к старым DNS-серверам. А перезагружать баунсеры категорически нельзя: есть проблемные проекты, которые очень болезненно относятся к разрывом сессий с базой.

В данной статье я расскажу как можно pgbouncer или любую другую программу, использующую библиотечный вызов getaddrinfo(), заставить перечитать resolv.conf и начать использовать новый DNS-сервер совершенно безболезненно для клиентов (без даунтайма).

Приступим

Сразу оговорюсь, что в моём случае pgbouncer’ы были версий 1.5.2 и собраны с libevent-1.4 под FreeBSD.

Если посмотреть в исходник pgbouncer’а, то можно увидеть в файле dnslookup.c следующий комментарий:

/* * Available backends: * * udns - libudns * getaddrinfo_a - glibc only * libevent1 - returns TTL, ignores hosts file. * libevent2 - does not return TTL, uses hosts file. */ 

Это означает, что в случае когда pgbouncer собран с libevent1, для асинхронного резолва адресов используется функция getaddrinfo_a() из стандартной библиотеки libc.
Опытным путём было установлено, что асинхронная getaddrinfo_a() использует обычную функцию getaddrinfo() из libc. На последнюю функцию мы и будем ставить точку останова. Этот факт избавит нас от необходимости собирать pgbouncer с отладочными символами, так как gdb знает функцию getaddrinfo, не смотря на то, что libc собрана без отладочных символов.

Добавим в конфиг pgbouncer’а несуществующую базу, ссылающуюся на несуществующий домен (пригодится для тестов):

test = host=test.xaxa.blabla12313212.su user=pgsql dbname=template1 pool_size=10 

В отдельном окне запустим pgbouncer:

su -m pgbouncer -c '/usr/local/bin/pgbouncer /usr/local/etc/pgbouncer.ini' 

В другом окне подключимся к процессу с помощью отладчика gdb:

gdb /usr/local/bin/pgbouncer `cat /var/run/pgbouncer/pgbouncer.pid` 

Поставим точку останова и позволим процессу выполняться дальше:

(gdb) b getaddrinfo Breakpoint 1 at 0x800f862a4 (gdb) c Continuing. 

В другом окне попробуем подключиться к нашей базе с несуществующим доменом, чтобы инициировать попытку резолва:

su -m pgbouncer -c 'export PGPASSWORD="123" && /usr/local/bin/psql -Utest test -h10.9.9.16 -p6000'; 

В gdb мы видим, что мы попали в яблочко:

Breakpoint 1, 0x0000000800f862a4 in getaddrinfo () from /lib/libc.so.7 (gdb) 
Как же работает getaddrinfo()?

С помощью мануалов и поисковика было выяснено, что эта функция при первом вызове читает файл resolv.conf, инициализирует в памяти структуру с кучей данных, среди которых можно найти и список DNS-серверов. Далее, функция пытается сделать резолв адреса при помощи первого адреса из списка. Если DNS-сервер не отвечает, функция делает активным следующий DNS-сервер из списка. И так по кругу. Функция читает resolv.conf только единожды.

Сначала я хотел пропатчить виртуальную память pgbouncer’а, найдя 4 байта адреса DNS-сервера в network order или host order формате. Для этого даже была написана программа «дампер памяти» на Си, которая позволяла дампить память процесса и искать определённый порядок байт. Но, как оказалось, в таком виде эти адреса в памяти найти невозможно. Понять же исходник getaddinfo() оказалось выше моих сил: очень много текста и всяческие goto чуть не сломали моё сознание. К тому же, я не являюсь программистом, а Си начал изучать всего месяц назад.

Кстати, моя программа, использующая ptrace и procfs подошла бы для pgbouncer’а собранного с libevent2: там ip-адреса DNS-серверов хранятся как раз в виде четырёх байт. Но описание данного опыта выходит за рамки статьи.

Что же делать?

К счастью, при помощи поисковика я нашёл в стандартной библиотеке спасительную функцию res_init():

The res_init() routine reads the configuration file (if any; see
resolver(5)) to get the default domain name, search list and the Internet
address of the local name server(s)

Именно эта функция вызывается при первом вызове getaddrinfo() и инициализирует нужную нам структуру!
Повторный же вызов функции переинициализирует структуру и перечитает resolv.conf.

Проверим на практике

Подключимся трассировщиком к нашему «замороженному» pgbouncer’у и начнём grep’ать файл дампа трассировки:

ktrace -f out.ktrace -p `cat /var/run/pgbouncer/pgbouncer.pid` kdump -l -f out.ktrace | grep resolv 

В окне с gdb осуществим вызов функции res_init():

(gdb) call res_init() Breakpoint 1, 0x0000000800f862a4 in getaddrinfo () from /lib/libc.so.7 

В окне с выводом результата трассировки мы видим:

37933 pgbouncer NAMI "/etc/resolv.conf" 
Цель достигнута

Нам удалось заставить процесс перечитать resolv.conf, при этом не уронив сервер и не разорвав активные state’ы tcp. В момент заморозки запросы также не теряются.

Если мы захотим чтобы локальный кэширующий DNS начал использоваться немедленно, нам нужно проделать следующие шаги:

  1. Поменять в forwarders BIND’а серверы на новые (другие) рабочие DNS’серверы, которые до этого не использовались в resolv.conf и не будут использоваться, а затем сделать rndc reload
  2. Забанить локальным фаерволом обращения к старым DNS-серверам (кроме 127.0.0.1)
  3. Инициировать обращение pgbouncer’a к несуществующему серверу БД:

su -m pgbouncer -c 'export PGPASSWORD="123" && /usr/local/bin/psql -Utest test -h127.0.0.1 -p6000'; 
tcpdump -n -i lo0 port 53 | grep xaxa "> 127.0.0.1.53" - 
И последнее

Если вы захотите повторить мой опыт, настоятельно рекомендую тренироваться на тестовом стенде.
Если вы захотите «пулять» команду в gdb в batch mode, имейте в виду, что gdb нужно сначала дать время на чтение символов, а потом уже следует вызывать функции: я как-то из-за этого здорово напортачил, убив один из 8-ми работающих pgbouncer’ов.
batch mode для gdb у меня выполняется теперь так:

printf 'shell sleep 3\ncall res_init()\ndetach\nquit\n' > /tmp/pb.gdb && gdb -batch -x /tmp/pb.gdb /usr/local/bin/pgbouncer `cat /var/run/pgbouncer/test.pid` 

Надеюсь, мой опыт кому-то поможет чуть лучше понять как работают процессы в операционных системах.

pgbouncer can not connect to server

userlist.txt also contains md5 encrypted password postgresql.conf file contains: listen_addresses = ‘*’ port = 4851 kindly help me how to remove this error.

2017-08-03 15:23:33.429 2360 LOG C-00EA8FE0: postgres/postgres@[::1]:54985 login attempt: db=postgres user=postgres tls=no 2017-08-03 15:23:33.429 2360 LOG C-00EA8FE0: postgres/postgres@[::1]:54985 closing because: pgbouncer cannot connect to server (age=0) 2017-08-03 15:23:33.430 2360 WARNING C-00EA8FE0: postgres/postgres@[::1]:54985 Pooler Error: pgbouncer cannot connect to server 

OperationalError: ERROR: pgbouncer cannot connect to server

I’m trying to do python manage.py syncdb on a Django installation, but I keep getting OperationalError: ERROR: pgbouncer cannot connect to server . pgbouncer.log contains lines such as:

2017-09-19 19:44:15.107 1128 LOG C-0x8a9930: mydb/myuser@unix:6432 closing because: pgbouncer cannot connect to server (age=0) 2017-09-19 19:44:15.107 1128 WARNING C-0x8a9930: mydb/myuser@unix:6432 Pooler Error: pgbouncer cannot connect to server 2017-09-19 19:44:15.107 1128 LOG S-0x8c72e0: mydb/[email protected]:5432 new connection to server 2017-09-19 19:44:15.107 1128 LOG C-0x8a9930: mydb/myuser@unix:6432 login failed: db=mydb user=myuser 2017-09-19 19:44:30.108 1128 LOG S-0x8c72e0: mydb/[email protected]:5432 closing because: connect failed (age=15) 

In case needed, ps -aef | grep pgbouncer yields:

postgres 1128 1 0 18:38 ? 00:00:00 /usr/sbin/pgbouncer -d /etc/pgbouncer/pgbouncer.ini myuser 1919 1533 0 19:45 pts/0 00:00:00 grep --color=auto pgbouncer 

Moreover, grep port /etc/pgbouncer/pgbouncer.ini results in:

;; dbname= host= port= user= password= mydb = host=xx.xxx.xxx.xxx port=5432 dbname=mydb ;forcedb = host=127.0.0.1 port=300 user=baz password=foo client_encoding=UNICODE datestyle=ISO connect_query='SELECT 1' listen_port = 6432 

Lastly, the relevant parts of settings.py contain:

DATABASES = < 'default': < 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'mydb', 'USER': 'myuser', 'PASSWORD': 'mypassword', 'HOST': '/var/run/postgresql', 'PORT': '6432', >

I turned log_connections to on in postgresql.conf, restarted PG and tried again. Here’s the relevant lines:

2017-09-20 07:50:59 UTC LOG: database system is ready to accept connections 2017-09-20 07:50:59 UTC LOG: autovacuum launcher started 2017-09-20 07:51:00 UTC LOG: connection received: host=[local] 2017-09-20 07:51:00 UTC LOG: incomplete startup packet 2017-09-20 07:51:00 UTC LOG: connection received: host=[local] 2017-09-20 07:51:00 UTC LOG: connection authorized: user=postgres database=postgres 2017-09-20 07:51:01 UTC LOG: connection received: host=[local] 2017-09-20 07:51:01 UTC LOG: connection authorized: user=postgres database=postgres 2017-09-20 07:51:01 UTC LOG: connection received: host=[local] 2017-09-20 07:51:01 UTC LOG: connection authorized: user=postgres database=postgres 

It seems the connection is going through, but the user and database name is postgres . Those credentials aren’t what I supplied in pgbouncer.ini . However, explicitly adding myuser in the connection string described in pgbouncer.ini leads to:

2017-09-20 09:37:37 UTC FATAL: Peer authentication failed for user "myuser" 2017-09-20 09:37:37 UTC DETAIL: Connection matched pg_hba.conf line 90: "local all all peer" 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *