Если вы видите что-то необычное, просто сообщите мне. Skip to main content

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адрес Postgres pod/deployment.дб
  • DB_USER: the Postgres database user.пользоатель
  • DB_PASSWORD: the Postgres databaseпользователь 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к Postgres whenдб, 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(в нашем случае)