Postgres connection pool для Kubernetes
MotivationПроблема
IfЕсли youвы developразрабатываете appsприложения usingиспользуя frameworksтакой suchфреймворк asкак Django oили RoR, youвы, haveскорей probablyвсего, facedсталкивались theсо followingследуюущей problem/error.проблемой:
FATAL: sorry, too many clients already
AsКак youвы know,знаете, theseэтот kindтип ofфрейморка frameworksиспользует usesпул aподключений databaseк connectionбазе poolданных, withс theцелью objectiveсократить ofвремя toработы reduceс theбазой database connection latency.данных.
That’sЭто isвсегда greatздорово alwaysкогда whichваша yourбд databaseнастроениа isобслуживать optimizedмножество to have a lot of connections.подключений.
AsКак youвы canможете infer,понять, it’sэто notне theслучай case ofс Postgres.
EachКаждое подключение postgres использует порядка 10mb, так же большую часть времени они находятся в ожидании.
Вместе с бумом gRPC потоков, всё стало хуже. У нас есть кучество подключений в ожидании, но Postgres connectionзапрашивает usesбольше aboutресурсов 10ни MB,на altoughчто, mostчтобы ofперевести theподключения timeв theyсостояние are idle.
With the microservices boom or gRPC streams, things get worse. We have a lot of idle connections but Postgres requests a lot of resources for nothing, to put in a idle state.ожидания.
PgBouncer toна the rescueпомощь
ThereЕсть areнесколько serveralрешений optionsдля toпроблем solveс theмножественными multipleподключениями connectionsно problemвсе butиз allних ofиспользуют themодин useи theтот sameже pattern:шаблон, aпрокси proxyпо in the middle.середине.
TheИдея ideaтакова, isвы thatподключаете youпотребителя connectк yourпрокси, consumerкоторый softwareпозволяет toмножество aдешовых proxyподключений, whichи allowsэтот aпрокси lotподключает of “cheap” connections, and this proxy connects with theк Postgres databaseбазе onlyданых whenтолько yourкогда appваше reallyприложение needдействительно toнеобходимо performпроизвести anyдействие databaseв action.дб.
OneОдно ofиз theseэтих solutionsрешений is- PgBouncer.PgBouncer.
It’sЭто theстарейшее oldestрешение solutionи andоно itsшироко adopted widely.используется.
Pgbouncer inв yourвашем кластере K8S cluster
To putЗапустить pgbouncer inв yourкластер clusterпроще isпаренной easy as pie.репы.
WeМы useбудем theиспользовать followingэтот docker image/project:образ: edoburu/pgbouncer
ToДля useначала justопределим weconfigmap, needуказав toследующие defineнастройки aдля configподключения and a secret K8S resources. We need to provide it the followingк Postgres database connection:дб:
- DB_HOST:
the K8S service name of yourадрес Postgrespod/deployment.дб - DB_USER:
thePostgresdatabase user.пользоатель - DB_PASSWORD:
thePostgresdatabaseпользовательuserбазы данных (youегоshouldнеобходимоstoreхранитьitвasзакрытомa secret)виде). - POOL_MODE:
specificуказываемpgbouncerпараметрparameter.вWeрежимеuse"transaction",“transaction”такmodeкакbecauseнужноweподключатьсяonly want to connect toк Postgreswhenдб,weкогдаreallyнамneedреальноit.это нужно. - SERVER_RESET_QUERY:
beforeпрошлыеaподключенияconnectionмогутcanбытьbeиспользованыreusedдругимиbyклиентами.otherОченьclient,важноit’sскдиыватьimportantпредыдущиеtoсессии.reset any previous session set.DISCARD ALL
ifиспользуетсяokдляforверсий Postgres 8.3+3<
Taking into account the above, the deployment manifest can be something as below
pgbouncer-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: pgbouncer-env
namespace: test
data:
DB_HOST:
DB_PASSWORD:
DB_USER:
POOL_MODE: transaction
SERVER_RESET_QUERY: DISCARD ALL
pgbouncer-deployment.yamlНастройки деплоймента должны выглядеть следующим образом:
#pgbouncer-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pgbouncer-deployment
namespace: test
labels:
app: pgbouncer-app
spec:
selector:
matchLabels:
app: pgbouncer-app
template:
metadata:
labels:
app: pgbouncer-app
spec:
containers:
- image: edoburu/pgbouncer:1.9.0
name: pgbouncer-pod
ports:
- containerPort: 5432
name: pgbouncer-p
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- all
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- killall -INT pgbouncer && sleep 120
envFrom:
- configMapRef:
name: pgbouncer-env
pgbouncer-service.yamlМы примеяем конфи используя стандартную команду(не забываем сначала создать configmap
, а затем деплоймент):
$ kubectl apply -f pgbouncer-configmap.yaml
$ kubectl apply -f pgbouncer-deployment.yaml
Осталось только создать сервис для протребителя.
#pgbouncer-service.yaml
apiVersion: v1
kind: Service
metadata:
name: pgbouncer-service
namespace: test
spec:
type: ClusterIP
selector:
app: pgbouncer-app
ports:
- name: pgbouncer
port: 5432
targetPort: pgbouncer-p
WeПрименяем canконфиг apply it using the standard CLI command (remember to create the config and/or secrets before!)
$ kubectl apply -f pgbouncer-deployment.yaml
Now, you just need to create the service to consume it.
We apply again the service manifestсервиса:
$ kubectl apply -f pgbouncer-service.yaml
AndВот that’sи all!всё!
Можно пользоваться, только не забудьте изменить DB_HOST
переменную в вашем деплойменте с postgres адреса на pgbouncer-service
(в нашем случае)