EDB Postgres Distributed Proxy overview
=======================================

Especially with asynchronous replication, having a consistent write
leader node is important to avoid conflicts and guarantee availability
for the application.

The two parts to EDB Postgres Distributed’s proxy layer are:

-  Proxy configuration and routing information, which is maintained by
   the PGD consensus mechanism.

-  The PGD Proxy service, which is installed on a host. It connects to
   the PGD cluster, where it reads its configuration and listens for
   changes to the routing information.

This is normally installed in highly available configuration (at least
two instances of the proxy service per PGD group).

Once configured, the PGD Proxy service monitors routing changes as
decided by the EDB Postgres Distributed cluster. It acts on these
changes to ensure that connections are consistently routed to the
correct nodes.

Configuration changes to the PGD Proxy service are made through the PGD
cluster. The PGD Proxy service reads its configuration from the PGD
cluster, but the proxy service must be restarted to apply those changes.

The information about currently selected write and read nodes is visible
in ``bdr.node_group_routing_summary`` . This is node-local view: the
proxy always reads from Raft leader to get a current and consistent
view.

Leader selection
----------------

The write leader is selected by the current Raft leader (either subgroup
one or top-level group one, depending on whether the leader for the
subgroup or the cluster’s top-level group is being selected).

Leader is selected from candidate nodes that are reachable and meet the
criteria based on the configuration as described in :ref:`PGD Proxy cluster configuration <PGD Proxy cluster configuration>`  . To
be a viable candidate, the node must have ``route_writes`` enabled and
``route_fence`` disabled and be within ``route_writer_max_lag`` (if
enabled) from the previous leader. The candidates are ordered by their
``route_priority`` in descending order and by the lag from the previous
leader in ascending order.

The new leader selection process is started either when there’s no
existing leader currently (this could be because there were no valid
candidates or because Raft was down) or when connectivity is lost to the
existing leader.

A node is considered connected if the last Raft protocol message
received from the leader isn’t older than Raft election timeout (see
:ref:`Internal settings - Raft timeouts  bdr.raft_global_election_timeout <Internal settings - Raft timeouts  bdr.raft_global_election_timeout>`  ).

Since the Raft leader is sending heartbeat 3 times every election
timeout limit, the leader node needs to miss the reply to 3 heartbeats
before it’s considered disconnected.

PGD Proxy cluster configuration
-------------------------------

The PGD cluster always has at least one top-level group and one data
group. PGD elects the write leader for each data group that has the
``enable_proxy_routing`` and ``enable_raft`` options set to true.

The cluster also maintains Proxy configurations for each group. Each
configuration has a name and is associated with a group. You can attach
Proxy to a top-level group or data group. You can attach multiple
proxies to each group.

When a PGD Proxy service starts running on a host, it has a name in its
local configuration file and it connects to a node in a group. From
there, it uses the name to look up its complete configuration as stored
on the group.

PGD Proxy service
-----------------

The EDB Postgres Distributed Proxy (PGD Proxy) service is a process that
acts as an abstraction layer between the client application and
Postgres. It interfaces with the PGD consensus mechanism to get the
identity of the current write leader node and redirects traffic to that
node. It also optionally supports a read-only mode where it can route
read-only queries to nodes that aren’t the write leader, improving the
overall performance of the cluster.

PGD Proxy is a TCP layer 4 proxy.

How they work together
----------------------

Upon starting, PGD Proxy connects to one of the endpoints given in the
local config file. It fetches:

-  DB connection information for all nodes

-  Proxy options like listen address, listen port

-  Routing details including the current write leader in default mode,
   read nodes in read-only mode, or both in any mode.

The endpoints given in the config file are used only at startup. After
that, actual endpoints are taken from the PGD catalog’s ``route_dsn``
field in :ref:`bdr.node_routing_config_summary <bdr.node_routing_config_summary>`  .

PGD manages write leader election. PGD Proxy interacts with PGD to get
write leader change events notifications on Postgres notify/listen
channels and routes client traffic to the current write leader. PGD
Proxy disconnects all existing client connections on write leader change
or when write leader is unavailable. Write leader election is a
Raft-backed activity and is subject to Raft leader availability. PGD
Proxy closes the new client connections if the write leader is
unavailable.

PGD Proxy responds to write leader change events that can be categorized
into two modes of operation: *failover* and *switchover*.

Automatic transfer of write leadership from the current write leader
node to a new node in the event of Postgres or operating system crash is
called *failover*. PGD elects a new write leader when the current write
leader goes down or becomes unresponsive. Once the new write leader is
elected by PGD, PGD Proxy closes existing client connections to the old
write leader and redirects new client connections to the newly elected
write leader.

User-controlled, manual transfer of write leadership from the current
write leader to a new target leader is called *switchover*. Switchover
is triggered through the :ref:`PGD CLI switchover <switchover>`  command. The command is submitted
to PGD, which attempts to elect the given target node as the new write
leader. Similar to failover, PGD Proxy closes existing client
connections and redirects new client connections to the newly elected
write leader. This is useful during server maintenance, for example, if
the current write leader node needs to be stopped for maintenance like a
server update or OS patch update.

If the proxy is configured to support read-only routing, it can route
read-only queries to a pool of nodes that are not the write leader. The
pool of nodes is maintained by the PGD cluster and proxies listen for
changes to the pool. When the pool changes, the proxy updates its
routing configuration and starts routing read-only queries to the new
pool of nodes and disconnecting existing client connections to nodes
that have left the pool.

Consensus grace period
^^^^^^^^^^^^^^^^^^^^^^

PGD Proxy provides the ``consensus_grace_period`` proxy option that can
be used to configure the routing behavior upon loss of a Raft leader.
PGD Proxy continues to route to the current write leader (if it’s
available) for this duration. If the new Raft leader isn’t elected
during this period, the proxy stops routing. If set to ``0s`` , PGD
Proxy stops routing immediately.

The main purpose of this option is to allow users to configure the write
behavior when the Raft leader is lost. When the Raft leader isn’t
present in the cluster, it’s not always guaranteed that the current
write leader seen by the proxy is the correct one. In some cases, like
network partition in the following example, it’s possible that the two
write leaders may be seen by two different proxies attached to the same
group, increasing the chances of write conflicts. If this isn’t the
behavior you want, then you can set the previously mentioned
``consensus_grace_period`` to 0s. This setting configures the proxy to
stop routing and closes existing open connections immediately when it
detects the Raft leader is lost.

Network partition example
^^^^^^^^^^^^^^^^^^^^^^^^^

Consider a 3-data node group with a proxy on each data node. In this
case, if the current write leader gets network partitioned or isolated,
then the data nodes present in the majority partition elect a new write
leader. If ``consensus_grace_period`` is set to a non-zero value, say
``10s`` , then the proxy present on the previous write leader continues
to route writes for this duration.

In this case, if the grace period is kept too high, then writes continue
to happen on the two write leaders. This condition increases the chances
of write conflicts.

Having said that, most of the time, upon loss of the current Raft
leader, the new Raft leader gets elected by BDR within a few seconds if
more than half of the nodes (quorum) are still up. Hence, if the Raft
leader is down but the write leader is still up, then proxy can be
configured to allow routing by keeping ``consensus_grace_period`` to a
non-zero, positive value. The proxy waits for the Raft leader to get
elected during this period before stopping routing. This might be
helpful in some cases where availability is more important.

Read consensus grace period
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Similar to the ``consensus_grace_period`` , a
``read_consensus_grace_period`` option is available for read-only
routing. This option can be used to configure the routing behavior upon
loss of a Raft leader for read-only queries. PGD Proxy continues to
route to the current read nodes for this duration. If the new Raft
leader isn’t elected during this period, the proxy stops routing
read-only queries. If set to ``0s`` , PGD Proxy stops routing read-only
queries immediately.

Multi-host connection strings
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The PostgreSQL C client library (libpq) allows you to specify multiple
host names in a single connection string for simple failover. This is
also supported by client libraries (drivers) in some other programming
languages. It works well for failing over across PGD Proxy instances
that are down or inaccessible.

However, if the PGD Proxy instance is accessible but doesn’t have access
to the write leader, or the write leader for a given instance doesn’t
exist (that is, because there’s no write leader for the given PGD
group), the connection simply fails. No other hosts in the multi-host
connection string is tried. This behavior is consistent with the
behavior of PostgreSQL client libraries with other proxies like HAProxy
or pgbouncer.
