вторник, 25 апреля 2017 г.

Базовая установка и настройка FreeRADIUS 3 в CentOS7 с поддержкой PostgreSQL

Базовая установка и настройка FreeRADIUS 3 в CentOS7 с поддержкой PostgreSQL.

Отключаем Firewall
# service firewalld stop
# chkconfig firewalld off

Установка пакетов, требующихся в дальнейшем:
# yum install libtalloc-devel –y
# yum install wget nano
# yum install gcc
# yum install tcpdump
# yum install openssl-devel
# yum install python-devel

Отключаем SELinux
# nano /etc/sysconfig/selinux
Комментируем все, вставляем строку
SELINUX=disabled
Перезагружаемся:
# reboot

Устанавливаем сервер PostgreSQL
# yum install postgresql-server
# yum install postgresql-devel
Устанавливаем расширения
# yum install postgresql-contrib
Производим инициализацию базы данных по умолчанию:
# service postgresql initdb
В дальнейшем с базой PostgreSQL можно работать при необходимости.

Переходим в папку установки:
# cd /usr/src/

Скачиваем архив с исходными кодами FreeRADIUS:
# wget ftp://ftp.freeradius.org/pub/freeradius/freeradius-server-3.0.13.tar.gz

Распаковываем архив:
# tar -xvzf freeradius-server-3.0.13.tar.gz

Переходим в распакованную папку:
# cd freeradius-server-3.0.13

Устанавливаем:
# ./configure
# make
# make install

Конфигурация FreeRADIUS, послу естановки находиться в директории /usr/local/etc/raddb/

Делаем первый запуск
# radiusd -X
Получаем ошибку:
Debugger not attached
Refusing to start with libssl version OpenSSL 1.0.1e-fips 11 Feb 2013 0x1000105f (1.0.1e release) (in range 1.0.1 release - 1.0.1t rele)
Security advisory CVE-2016-6304 (OCSP status request extension)
For more information see https://www.openssl.org/news/secadv/20160922.txt
Once you have verified libssl has been correctly patched, set security.allow_vulnerable_openssl = 'CVE-2016-6304'
Refusing to start with libssl version OpenSSL 1.0.1e-fips 11 Feb 2013 0x1000105f (1.0.1e release) (in range 1.0.1 dev - 1.0.1f release)
Security advisory CVE-2014-0160 (Heartbleed)
For more information see http://heartbleed.com 
Исправление ошибки выполняется установкой параметра allow_vulnerable_openssl в настройках
# nano /usr/local/etc/raddb/radiusd.conf
По умолчанию:
allow_vulnerable_openssl = no
Меняем на 
allow_vulnerable_openssl = 'CVE-2016-6304'
Теперь после тестового запуска radius сервера старт завершается успешно:
# radiusd -X
FreeRADIUS Version 3.0.13
Copyright (C) 1999-2017 The FreeRADIUS server project and contributors
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A

Listening on auth address * port 1812 bound to server default
Listening on acct address * port 1813 bound to server default
Listening on auth address :: port 1812 bound to server default
Listening on acct address :: port 1813 bound to server default
Listening on auth address 127.0.0.1 port 18120 bound to server inner-tunnel
Listening on proxy address * port 35712
Listening on proxy address :: port 37586
Ready to process requests
Остановка запущенного в тесте сервера:
CTRL +C

Удаляем шаблоны, работающие по умолчанию default и inner-tunnel
# rm –f /usr/local/etc/raddb/sites-enabled/inner-tunnel
# rm -f /usr/local/etc/raddb/sites-enabled/default

Отключаем проксирование
# nano /usr/local/etc/raddb/radiusd.conf
Строки
proxy_requests  = yes
$INCLUDE proxy.conf
Меняем на
proxy_requests  = no
#$INCLUDE proxy.conf

Отключаем логирование модуля unix
# nano /usr/local/etc/raddb/mods-enabled/unix
Комментируем строку
# radwtmp = ${logdir}/radwtmp
Это указание не вести логирование в файле /usr/local/var/log/radius/radwtmp

Учим FREERADIUS работать с атрибутами Cisco AV-Pair
# nano /usr/local/etc/raddb/mods-enabled/preprocess
Устанавливаем директиву with_cisco_vsa_hack в yes (по умолчанию no)
    with_cisco_vsa_hack = yes
# systemctl restart radiusd.service
Словари лежат здесь /usr/local/share/freeradius/dictionary
Для успешного приема атрибутов, передаваемых в Cisco AV Pair необходимо явно прописать их в настройках словарей FreeRADIUS.
# nano /usr/local/share/freeradius/dictionary.cisco
После блока SIP атрибутов (# SIP Attributes) пишем новые атрибуты
# Новые атрибуты
ATTRIBUTE       client-mac-address                      171     string
ATTRIBUTE       connect-progress                        172     string
ATTRIBUTE       ppp-disconnect-cause                    173     string
ATTRIBUTE       disc-cause-ext                          174     string
ATTRIBUTE       circuit-id-tag                          175     string
Теперь в логах вместо атрибута 
Cisco-AVPair = "client-mac-address=107b.ef5c.2579"
Будет две строки
Cisco-AVPair = "client-mac-address=2cb0.5d81.b453"
client-mac-address = "2cb0.5d81.b453"
То же для атрибутов connect-progress, ppp-disconnect-cause, disc-cause-ext, circuit-id-tag
И названия атрибутов client-mac-address, connect-progress и пр. можно будет использовать напрямую.

Меняем название файла логов аккаутинга, для того что бы можно было его успешно ротировать
# nano /usr/local/etc/raddb/mods-enabled/detail
Меняем строку
filename = ${radacctdir}/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d
на
filename = ${radacctdir}/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail
Логи сервера находятся в файле: /usr/local/var/log/radius/radius.log
Логи аккаутинга складываются в папку: /usr/local/var/log/radius/radacct/<ip-адрес-клиента>/
Организовываем ротацию файлов логов 
# cp /usr/src/freeradius-server-3.0.13/redhat/freeradius-logrotate /etc/logrotate.d/
# nano /etc/logrotate.d/freeradius-logrotate
Содержимое файла может быть таким:
/usr/local/var/log/radius/radius.log {
        rotate 2
        copytruncate
        missingok
        daily
        size=500k
        nomail
}
/usr/local/var/log/radius/radacct/*/detail {
        rotate 2
        noolddir
        nocopy
        create
        nocopytruncate
        missingok
        daily
        size=10M
        nomail
        postrotate
                /usr/bin/systemctl restart radiusd.service
        endscript
}
В заключении выполняем проверку правил ротации логов:
# logrotate -d /etc/logrotate.d/freeradius-logrotate
Принудительный запуск ротации:
# logrotate -f /etc/logrotate.d/freeradius-logrotate
Посмотреть что и когда ротировалось можно в файле /var/lib/logrotate.status

Создаем и подключаем свой модуль sql, которым будем пользоваться.
# cp /usr/local/etc/raddb/mods-available/sql /usr/local/etc/raddb/mods-available/sql_my
# ln -s /usr/local/etc/raddb/mods-available/sql_my /usr/local/etc/raddb/mods-enabled/sql_my
Редактируем модуль:
# nano /usr/local/etc/raddb/mods-enabled/sql_my
Здесь пока можно все закомментировать или удалить.
Для удаления всего содержимого выполняем:
# echo "" > /usr/local/etc/raddb/mods-enabled/sql_my

Создаем свой тестовый шаблон на основе имеющегося:
# cp /usr/local/etc/raddb/sites-available/default /usr/local/etc/raddb/sites-available/test
# ln -s /usr/local/etc/raddb/sites-available/test /usr/local/etc/raddb/sites-enabled/test
Теперь после запуска сервера мы имеем корректно запущенный сервер FreeRADIUS, прослушивающий порты 1812 и  1813.
# radiusd -X

Listening on auth address * port 1812 bound to server default
Listening on acct address * port 1813 bound to server default
Listening on auth address :: port 1812 bound to server default
Listening on acct address :: port 1813 bound to server default
Ready to process requests
Для проверки, в другой консоли набираем команду проверки открытых портов службами:
# netstat -ltupn | grep radius
udp        0      0 0.0.0.0:1812     0.0.0.0:*           1898/radiusd
udp     2176      0 0.0.0.0:1813     0.0.0.0:*           1898/radiusd
udp6       0      0 :::1812           :::*                1898/radiusd
udp6       0      0 :::1813           :::*                1898/radiusd

Внедряем unit FreeRADIUS в службу systemd
Копируем имеющийся в скаченном архиве готовый файл юнита:
# cp /usr/src/freeradius-server-3.0.13/redhat/radiusd.service /etc/systemd/system/multi-user.target.wants/
# chmod +x /etc/systemd/system/multi-user.target.wants/radiusd.service
Редактируем файл 
# nano /etc/systemd/system/multi-user.target.wants/radiusd.service
и приводим его к виду:
[Unit]
Description=FreeRADIUS multi-protocol policy server
After=network.target
Documentation=man:radiusd(8) man:radiusd.conf(5) http://wiki.freeradius.org/ http://networkradius.com/doc/

[Service]
Type=forking
EnvironmentFile=-/etc/sysconfig/radiusd
ExecStartPre=/usr/local/sbin/radiusd $FREERADIUS_OPTIONS -Cxm -lstdout
ExecStart=/usr/local/sbin/radiusd $FREERADIUS_OPTIONS -m
Restart=on-failure
RestartSec=5
ExecReload=/usr/local/sbin/radiusd $FREERADIUS_OPTIONS -Cxm -lstdout
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target
Рестартуем демон systemd:
# systemctl daemon-reload
Теперь запуск сервера выполняем так:
# systemctl start radiusd.service
Статус:
# systemctl status radiusd.service
Остановка сервера:
# systemctl stop radiusd.service

суббота, 15 апреля 2017 г.

Установка и настройка Postgres-XL в CentOS7



Устанавливаем необходимые пакеты:
# yum install nano wget
# yum install glibc gcc make autoconf automake libtool glib2 pcre slang gettext
# yum groupinstall 'Development Tools'
# yum install cvs
# yum install readline-devel
# yum install zlib-devel
# yum install net-tools
# yum install python-devel 

Отключаем возможность установки старых версий PostgreSQL из стандартного репозитария:
# nano /etc/yum.repos.d/CentOS-Base.repo
Добавляем в секции [base] и [updates] строку
exclude=postgresql*
# yum update

Отключаем SELinux
# nano /etc/sysconfig/selinux
Комментируем все, вставляем строку
SELINUX=disabled
Перезагружаемся:
# reboot

Отключаем firewall в CentOS 7
# service firewalld stop
# chkconfig firewalld off

Заходим в каталог /usr/src/
# cd /usr/src/

Скачиваем со страницы загрузки http://www.postgres-xl.org/download/ пакет исходных кодов:
# wget http://files.postgres-xl.org/postgres-xl-9.5r1.4.tar.gz
Распаковываем архив:
# tar -xvzf postgres-xl-9.5r1.4.tar.gz
Переходим в архив:
# cd postgres-xl-9.5r1.4

Конфигурируем и собираем:
# ./configure
Или лучше для конфигурирования с модулем PL/Python:
# ./configure --with-python
Затем:
# gmake
Сборка заканчивается сообщением:
All of Postgres-XL successfully made. Ready to install.
Выполняем установку:
# gmake install
Установка завершается сообщением:
Postgres-XL installation complete.
Установка по умолчанию выполняется в директорию /usr/local/pgsql/

Если ранее в системе не было установлено экземпляра базы данных PostgreSQL, то значит не было создано пользователя postgres, который необходим для работы.
Проверить существование пользователя postgres можно так:
# cat /etc/passwd | grep postgres
postgres:x:26:26:PostgreSQL Server:/var/lib/pgsql:/bin/bash
У меня в системе он уже был.
Если пользователя postgres нет, то cоздание пользователя выполняем так:
# adduser postgres

Прописываем переменные, требуемые для корректного запуска:
# echo 'export PGUSER=postgres' >> /etc/profile
# echo 'export PGHOME=/usr/local/pgsql' >> /etc/profile
# echo 'export PATH=$PATH:$PGHOME/bin' >> /etc/profile
# echo 'export LD_LIBRARY_PATH=$PGHOME/lib' >> /etc/profile

Процедуру установки неоюходимо сделать на каждом сервере, на котором будет разварачиваться кластер Postgres-XL

Postgres-XL состоит из трех основных компонентов:
Global Transaction Monitor (GTM) – Глобальный монитор транзакций, который следит за тем, что бы данные в кластере были актуальными и все запросы к данным завершились успешно.
Coordinator – Координатор. Элемент обеспечивающий связь пользователя с узлами данных Data Node. Координатор сам разберет сложный запрос, запросит данные у узлов, соберет их вместе и вернут пользователю.
Data Node – Узел данных, работающий непосредственно с данными.
Так как GTM, является узлов, при выходе которого из строя рушиться система, GTMов делают два – Основной (master) и резервный (slave).
Решение Postgres-XL ориентировано на установку составных элементов в одной высоконадежной сети. То есть распределенное хранилище данных, с разнесением элементов по разным городам работать будет плохо.


Рекомендуют координаторов сделать столько же, сколько узлов данных и на каждом сервере размещать по элементу Coordinator + Data Node. Для GTM в документации рекомендуют отдельный сервер. Каждому элементу Data Node и Coordinator нужны заданные порты (port) для приема сообщений Postgres и порты (pooler port) для подключения к другим узлам кластера. Порты pooler port должны быть разные на всех узлах кластера.
Наша конфигурация будет такая:


Предполагается, что на обеих машинах проведена инсталляция пакета Postgres-XL.

Все элементы Postgres-XL – это отдельные экземпляры базы данных PostgreSQL, которые необходимо инициировать в разных каталогах. Для этого необходимо эти каталоги создать и назначить на них права пользователю postgres

Создаем на сервере №1 каталоги для узлов системы:
# mkdir /usr/local/pgsql/data_coord1
# mkdir /usr/local/pgsql/data_datanode_1
# mkdir /mnt/data_datanode_2
# mkdir /usr/local/pgsql/data_gtm
# chown postgres /usr/local/pgsql/data_coord1
# chown postgres /usr/local/pgsql/data_datanode_1
# chown postgres /mnt/data_datanode_2
# chown postgres /usr/local/pgsql/data_gtm
Создаем на сервере №2 каталоги для узлов системы:
# mkdir /usr/local/pgsql/data_coord
# mkdir /usr/local/pgsql/data_datanode
# mkdir /usr/local/pgsql/data_gtm
# chown postgres /usr/local/pgsql/data_coord
# chown postgres /usr/local/pgsql/data_datanode
# chown postgres /usr/local/pgsql/data_gtm

Проводим инициирование узлов на сервере №1
Инициирование узлов кластера выполняется из под пользователя postgres, поэтому переходим в консоль пользователя postgres:
# su - postgres
Последний вход в систему:Сб мар 25 14:53:06 MSK 2017на pts/0
-bash-4.2$
Выполняем инициирование GTM на сервере №1
-bash-4.2$ /usr/local/pgsql/bin/initgtm -D /usr/local/pgsql/data_gtm -Z gtm
Опция D указывает в каком каталоге инициировать GTM узел. Опция Z указывает какой тип GTM нужно создать (gtm или gtm-proxy). Мы создаем GTM.
Вывод команды:
The files belonging to this GTM system will be owned by user "postgres".
This user must also own the server process.

fixing permissions on existing directory /usr/local/pgsql/data_gtm ... ok
creating configuration files ... ok
creating control file ... ok

Success.
You can now start the GTM server using:

    /usr/local/pgsql/bin/gtm -D /usr/local/pgsql/data_gtm
or
    /usr/local/pgsql/bin/gtm_ctl -Z gtm -D /usr/local/pgsql/data_gtm -l logfile start

Выполняем инициирование координатора на сервере №1
-bash-4.2$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data_coord1 --nodename coord1
Процесс инициирования отображается на экране:
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "ru_RU.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "russian".

Data page checksums are disabled.

fixing permissions on existing directory /usr/local/pgsql/data_coord1 ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
creating template1 database in /usr/local/pgsql/data_coord1/base/1 ... ok
initializing pg_authid ... ok
initializing dependencies ... ok
creating system views ... ok
creating cluster information ... ok
loading system objects' descriptions ... ok
creating collations ... ok
creating conversions ... ok
creating dictionaries ... ok
setting privileges on built-in objects ... ok
creating information schema ... ok
loading PL/pgSQL server-side language ... ok
vacuuming database template1 ... ok
copying template1 to template0 ... ok
copying template1 to postgres ... ok
syncing data to disk ... ok
freezing database template0 ... ok
freezing database template1 ... ok
freezing database postgres ... ok

WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

Success.
You can now start the database server of the Postgres-XL coordinator using:

    /usr/local/pgsql/bin/postgres --coordinator -D /usr/local/pgsql/data_coord1
or
    /usr/local/pgsql/bin/pg_ctl start -D /usr/local/pgsql/data_coord1 -Z coordinator -l logfile

 You can now start the database server of the Postgres-XL datanode using:

    /usr/local/pgsql/bin/postgres --datanode -D /usr/local/pgsql/data_coord1
or
    /usr/local/pgsql/bin/pg_ctl start -D /usr/local/pgsql/data_coord1 -Z datanode -l logfile

Выполняем инициирование узла datanode в каталоге /usr/local/pgsql/data_datanode_1 на сервере №1
-bash-4.2$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data_datanode_1 --nodename datanode_1
Процесс инициирования практически ничем не отличается от предыдущего.

Выполняем инициирование узла datanode в каталоге /mnt/data_datanode_2 на сервере №1
-bash-4.2$ /usr/local/pgsql/bin/initdb -D /mnt/data_datanode_2 --nodename datanode_2
Процесс инициирования так же не примечателен.

Проводим инициирование узлов на сервере №2
Выполняем инициирование GTM на сервере №2
$ /usr/local/pgsql/bin/initgtm -D /usr/local/pgsql/data_gtm -Z gtm
Выполняем инициирование координатора на сервере №2
$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data_coord --nodename coord2
Выполняем инициирование узла datanode в каталоге /usr/local/pgsql/data_datanode на сервере №2
$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data_datanode --nodename datanode_3

Во время инициирования узлов кластера, в каждой директории создаются каталоги, которые будут содержать базы данных и файлы конфигураций.
Необходимо провести конфигурирование узлов кластера.
GTM сервера №1
$ nano /usr/local/pgsql/data_gtm/gtm.conf
Вписываем имя nodename. Снимаем комментарий с директив listen_addresses и startup.
Разрешаем логирование путям снятия комментария с директив log_file и log_min_messages.
#------------------------------------------------------------------
# GENERAL PARAMETERS
#------------------------------------------------------------------
nodename = 'gtm1'                 # Specifies the node name.
                                  # (changes requires restart)
listen_addresses = '*'            # Listen addresses of this GTM.
                                  # (changes requires restart)
port = 6666                       # Port number of this GTM.
                                  # (changes requires restart)

startup = ACT                     # Start mode. ACT/STANDBY.


#---------------------------------------
# OTHER OPTIONS
#---------------------------------------
#keepalives_idle = 0              # Keepalives_idle parameter.
#keepalives_interval = 0          # Keepalives_interval parameter.
#keepalives_count = 0             # Keepalives_count
log_file = 'gtm.log'              # Log file name
log_min_messages = WARNING        # log_min_messages.  

Coordinator сервера №1
$ nano /usr/local/pgsql/data_coord1/postgresql.conf
Здесь определяем директивой listen_addresses прослушивать все интерфейсы на порту 5433 (port = 5433). Задается pooler_port – номер порта, по которому координатор будет коннектится к узлам datanode. Здесь же происывается информация, необходимая для соединения с GTM. Директивой pgxc_node_name задается имя узла.
#listen_addresses = 'localhost'  # what IP address(es) to listen on;
listen_addresses ='*'          # comma-separated list of addresses;
                               # defaults to 'localhost'
                               # (change requires restart)
port = 5433                    # (change requires restart)


pooler_port = 40100            # Pool Manager TCP port
                               # (change requires restart)


gtm_host = '10.10.49.152'      # Host name or address of GTM
                               # (change requires restart)
gtm_port = 6666                # Port of GTM
                               # (change requires restart)
pgxc_node_name = 'coord1'      # Coordinator or Datanode name
                               # (change requires restart)
Далее необходимо задать права доступа к координатору в файле pg_hba.conf
$ nano /usr/local/pgsql/data_coord1/pg_hba.conf
В файле добавляем строку, разрешающую соединение с узлом из сети 10.10.0.0/16 и комментируем строку, описывающую подключение по IPv6
# IPv4 local connections:
host    all             all          127.0.0.1/32            trust
host    all             all          10.10.0.0/16            trust
# IPv6 local connections:
#host    all             all         ::1/128                 trust

Data Node 1 сервера №1 (в директории /usr/local/pgsql/data_datanode_1)
$ nano /usr/local/pgsql/data_datanode_1/postgresql.conf
Задаем директивы listen_addresses, port, pooler_port. Определяем параметры подключения к GTM и имя узла.
#listen_addresses = 'localhost' # what IP address(es) to listen on;
listen_addresses = '*'          # comma-separated list of addresses;
                                # defaults to 'localhost'
                                # (change requires restart)
port = 15432                    # (change requires restart)


pooler_port = 40101             # Pool Manager TCP port
                                # (change requires restart)


gtm_host = '10.10.49.152'      # Host name or address of GTM
                               # (change requires restart)
gtm_port = 6666                # Port of GTM
                               # (change requires restart)
pgxc_node_name = 'datanode_1'  # Coordinator or Datanode name
                               # (change requires restart)
Права доступа к узлу задаем в файле pg_hba.conf
$ nano /usr/local/pgsql/data_datanode_1/pg_hba.conf
В файле добавляем строку, разрешающую соединение с узлом из сети 10.10.0.0/16 и комментируем строку, описывающую подключение по IPv6
# IPv4 local connections:
host    all             all       127.0.0.1/32            trust
host    all             all       10.10.0.0/16            trust
# IPv6 local connections:
#host    all             all      ::1/128                 trust

Data Node 2 сервера №1 (в директории /mnt/data_datanode_2)
$ nano /mnt/data_datanode_2/postgresql.conf
Задаем директивы listen_addresses, port, pooler_port. Определяем параметры подключения к GTM и имя узла.
#listen_addresses = 'localhost' # what IP address(es) to listen on;
listen_addresses = '*'          # comma-separated list of addresses;
                                # defaults to 'localhost'
                                # (change requires restart)
port = 15433                    # (change requires restart)


pooler_port = 40102             # Pool Manager TCP port
                                # (change requires restart)


gtm_host = '10.10.49.152'       # Host name or address of GTM
                                # (change requires restart)
gtm_port = 6666                 # Port of GTM
                                # (change requires restart)
pgxc_node_name = 'datanode_1'   # Coordinator or Datanode name
                                # (change requires restart)
Права доступа к узлу задаем в файле pg_hba.conf
$ nano /mnt/data_datanode_2/pg_hba.conf
В файле добавляем строку, разрешающую соединение с узлом из сети 10.10.0.0/16 и комментируем строку, описывающую подключение по IPv6
# IPv4 local connections:
host    all             all         127.0.0.1/32            trust
host    all             all         10.10.0.0/16            trust
# IPv6 local connections:
#host    all             all        ::1/128                 trust

GTM сервера №2
$ nano /usr/local/pgsql/data_gtm/gtm.conf
#------------------------------------------------------------------
# GENERAL PARAMETERS
#------------------------------------------------------------------
nodename = 'gtm2'                 # Specifies the node name.
                                  # (changes requires restart)
listen_addresses = '*'            # Listen addresses of this GTM.
                                  # (changes requires restart)
port = 6666                       # Port number of this GTM.
                                  # (changes requires restart)

startup = STANDBY                 # Start mode. ACT/STANDBY.
#------------------------------------------------------------------
# GTM STANDBY PARAMETERS
#------------------------------------------------------------------
#Those parameters are effective when GTM 
# is activated as a standby server
active_host = '10.10.49.152'      # Listen address of active GTM.
                                  # (changes requires restart)
active_port = 6666                # Port number of active GTM.
                                  # (changes requires restart)

#---------------------------------------
# OTHER OPTIONS
#---------------------------------------
keepalives_idle = 15             # Keepalives_idle parameter.
keepalives_interval = 15         # Keepalives_interval parameter.
keepalives_count = 3             # Keepalives_count 
log_file = 'gtm.log'             # Log file name
log_min_messages = WARNING       # log_min_messages.  
                                 #Default WARNING.    
synchronous_backup = on 
Здесь кроме параметров, используемых и на основном GTM необходимо задать параметры основного GTM сервера: active_host и active_port

Coordinator сервера №2
$ nano /usr/local/pgsql/data_coord/postgresql.conf
#listen_addresses = 'localhost'  # what IP address(es) to listen on;
listen_addresses ='*'            # comma-separated list of addresses;
                                 # defaults to 'localhost'
                                 # (change requires restart)
port = 5433                      # (change requires restart)


pooler_port = 40103              # Pool Manager TCP port
                                 # (change requires restart)


gtm_host = '10.10.49.152'        # Host name or address of GTM
                                 # (change requires restart)
gtm_port = 6666                  # Port of GTM
                                 # (change requires restart)
pgxc_node_name = 'coord2'        # Coordinator or Datanode name
                                 # (change requires restart)
Далее необходимо задать права доступа к координатору в файле pg_hba.conf
$ nano /usr/local/pgsql/data_coord/pg_hba.conf
# IPv4 local connections:
host    all             all        127.0.0.1/32            trust
host    all             all        10.10.0.0/16            trust
# IPv6 local connections:
#host    all             all       ::1/128                 trust

Data Node сервера №2 (в директории /usr/local/pgsql/data_datanode)
$ nano /usr/local/pgsql/data_datanode/postgresql.conf
Задаем директивы listen_addresses, port, pooler_port. Определяем параметры подключения к GTM и имя узла.
#listen_addresses = 'localhost' # what IP address(es) to listen on;
listen_addresses = '*'          # comma-separated list of addresses;
                                # defaults to 'localhost'
                                # (change requires restart)
port = 15432                    # (change requires restart)


pooler_port = 40104             # Pool Manager TCP port
                                # (change requires restart)


gtm_host = '10.10.49.152'       # Host name or address of GTM
                                # (change requires restart)
gtm_port = 6666                 # Port of GTM
                                # (change requires restart)
pgxc_node_name = 'datanode_3'   # Coordinator or Datanode name
                                # (change requires restart)
Права доступа к узлу задаем в файле pg_hba.conf
$ nano /usr/local/pgsql/data_datanode/pg_hba.conf
# IPv4 local connections:
host    all             all        127.0.0.1/32            trust
host    all             all        10.10.0.0/16            trust
# IPv6 local connections:
#host    all             all       ::1/128                 trust

Запуск кластера
Запуск GTM выполняется в консоли пользователя postgres вот так
$ gtm_ctl start -Z gtm -D /usr/local/pgsql/data_gtm >logfile_gtm 2>&1 &
[1] 28366
Остановка выполняется так:
$ gtm_ctl stop -Z gtm -D /usr/local/pgsql/data_gtm
waiting for server to shut down.... done
server stopped
Команды для обоих серверов №1 и №2 одинаковы.

Запуск координаторов выполняется командой pg_ctl
На сервере №1
$ pg_ctl start -D /usr/local/pgsql/data_coord1 -Z coordinator -l logfile_coord 2>&1 &
На сервере №2
$ pg_ctl start -D /usr/local/pgsql/data_coord -Z coordinator -l logfile_coord 2>&1 &
Пример остановки координатора:
$ pg_ctl stop -D /usr/local/pgsql/data_coord1 -Z coordinator

Запуск Data Node выполняется так же командой pg_ctl
На сервере №1 запускаем две ноды:
$ pg_ctl start -D /usr/local/pgsql/data_datanode_1 -Z datanode -l logfile_datanode_1 2>&1 &
$ pg_ctl start -D /mnt/data_datanode_2 -Z datanode -l logfile_datanode_2 2>&1 &
На сервере №2 запускается одна нода:
$ pg_ctl start -D /usr/local/pgsql/data_datanode -Z datanode -l logfile_datanode 2>&1 &
Пример остановки ноды:
$ pg_ctl stop -D /mnt/data_datanode_2 -Z datanode

Убеждаемся, что все порты, определенные в конфигах кластера прослушиваются командой netstat, запускаемой из-под пользователя root.
# netstat -ltupn | grep 'postgres'
# netstat -ltupn | grep 'gtm'

После запуска кластера, необходимо каждому узлу кластера «рассказать» конфигурацию всей системы. Рассказывать конфигурацию будем через координаторы.
Подключаемся к первому координатору на сервере №1:
# su - postgres
$ psql -p 5433
psql (PGXL 9.5r1.4, based on PG 9.5.5 (Postgres-XL 9.5r1.4))
Type "help" for help.
postgres=#
Удаляем текущую конфигурацию:
postgres=# delete from pgxc_node;
DELETE 1
Создаем конфигурацию кластера:
postgres=# create node coord1 with (type=coordinator, host='10.10.49.152', port=5433);
postgres=# create node datanode_1 with (type=datanode, host='10.10.49.152', port=15432);
postgres=# create node datanode_2 with (type=datanode, host='10.10.49.152', port=15433);
postgres=# create node coord2 with (type=coordinator, host='10.10.49.154', port=5433);
postgres=# create node datanode_3 with (type=datanode, host='10.10.49.154', port=15432);
Перезагружаем узел
postgres=# SELECT pgxc_pool_reload();
 pgxc_pool_reload
------------------
 t
(1 row)
Смотрим, что получилось:
postgres=# select * from pgxc_node;
Через координатор №1 рассказываем конфигурацию системы узлу datanode_1 сервера №1. Удалить конфигурацию удаленно через EXECUTE DIRECT ON нельзя. Будем менять параметры.
postgres=# EXECUTE DIRECT ON (datanode_1) 'create node coord1 with (type=coordinator, host=''10.10.49.152'', port=5433)';
postgres=# EXECUTE DIRECT ON (datanode_1) 'create node datanode_2 with (type=datanode, host=''10.10.49.152'', port=15433)';
postgres=# EXECUTE DIRECT ON (datanode_1) 'create node coord2 with (type=coordinator, host=''10.10.49.154'', port=5433)';
postgres=# EXECUTE DIRECT ON (datanode_1) 'create node datanode_3 with (type=datanode, host=''10.10.49.154'', port=15432)';
postgres=# EXECUTE DIRECT ON (datanode_1) 'ALTER NODE datanode_1 WITH (TYPE = ''datanode'', HOST = ''10.10.49.152'', PORT = 15432)';
postgres=# EXECUTE DIRECT ON (datanode_1) 'SELECT pgxc_pool_reload()';
postgres=# EXECUTE DIRECT ON (datanode_1) 'select * from pgxc_node';
Через координатор №1 рассказываем конфигурацию системы узлу datanode_2 сервера №1
postgres=# EXECUTE DIRECT ON (datanode_2) 'create node coord1 with (type=coordinator, host=''10.10.49.152'', port=5433)';
postgres=# EXECUTE DIRECT ON (datanode_2) 'create node datanode_1 with (type=datanode, host=''10.10.49.152'', port=15432)';
postgres=# EXECUTE DIRECT ON (datanode_2) 'create node coord2 with (type=coordinator, host=''10.10.49.154'', port=5433)';
postgres=# EXECUTE DIRECT ON (datanode_2) 'create node datanode_3 with (type=datanode, host=''10.10.49.154'', port=15432)';
postgres=# EXECUTE DIRECT ON (datanode_2) 'ALTER NODE datanode_2 WITH (TYPE = ''datanode'', HOST = ''10.10.49.152'', PORT = 15433)';
postgres=# EXECUTE DIRECT ON (datanode_2) 'SELECT pgxc_pool_reload()';
postgres=# EXECUTE DIRECT ON (datanode_2) 'select * from pgxc_node';
Через координатор №1 рассказываем конфигурацию системы узлу datanode_3 сервера №2
postgres=# EXECUTE DIRECT ON (datanode_3) 'create node coord1 with (type=coordinator, host=''10.10.49.152'', port=5433)';
postgres=# EXECUTE DIRECT ON (datanode_3) 'create node datanode_1 with (type=datanode, host=''10.10.49.152'', port=15432)';
postgres=# EXECUTE DIRECT ON (datanode_3) 'create node coord2 with (type=coordinator, host=''10.10.49.154'', port=5433)';
postgres=# EXECUTE DIRECT ON (datanode_3) 'create node datanode_2 with (type=datanode, host=''10.10.49.152'', port=15433)';
postgres=# EXECUTE DIRECT ON (datanode_3) 'ALTER NODE datanode_3 WITH (TYPE = ''datanode'', HOST = ''10.10.49.154'', PORT = 15432)';
postgres=# EXECUTE DIRECT ON (datanode_3) 'SELECT pgxc_pool_reload()';
postgres=# EXECUTE DIRECT ON (datanode_3) 'select * from pgxc_node';
Через координатор №1 рассказываем конфигурацию системы узлу coord2 сервера №2
postgres=# EXECUTE DIRECT ON (coord2) 'create node coord1 with (type=coordinator, host=''10.10.49.152'', port=5433)';
postgres=# EXECUTE DIRECT ON (coord2) 'create node datanode_1 with (type=datanode, host=''10.10.49.152'', port=15432)';
postgres=# EXECUTE DIRECT ON (coord2) 'create node datanode_2 with (type=datanode, host=''10.10.49.152'', port=15433)';
postgres=# EXECUTE DIRECT ON (coord2) 'create node datanode_3 with (type=datanode, host=''10.10.49.154'', port=15432)';
postgres=# EXECUTE DIRECT ON (coord2) 'ALTER NODE coord2 WITH (TYPE = ''coordinator'', HOST = ''10.10.49.154'', PORT = 5433)';
postgres=# EXECUTE DIRECT ON (coord2) 'SELECT pgxc_pool_reload()';
postgres=# EXECUTE DIRECT ON (coord2) 'select * from pgxc_node';

Добавляем Postgres-XL в автозагрузку. Для этого создаем файлы unit для systemd.
# touch /etc/systemd/system/postgres-xl-start.service
# chmod 664 /etc/systemd/system/postgres-xl-start.service
# nano /etc/systemd/system/postgres-xl-start.service
Содержимое файла:
[Unit]
Description=Claster Postgres XL Start
After=network.target

[Service]
#Type=notify
Type=oneshot
User=root
ExecStart=/usr/bin/start_postgres_xl.sh
#ExecStop=/usr/local/pgsql/bin/gtm_ctl stop -Z gtm -D /usr/local/pgsql/data_gtm
#TimeoutSec=20s

[Install]
WantedBy=multi-user.target
Файл /usr/bin/start_postgres_xl.sh должен содержать команды для запуска кластера Postgres-XL
# touch /usr/bin/start_postgres_xl.sh
# chmod +x /usr/bin/start_postgres_xl.sh
# nano /usr/bin/start_postgres_xl.sh
Для сервера №1 файл будет таким:
#! /bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
set -e
su - postgres -c '/usr/local/pgsql/bin/pg_ctl -Z coordinator start -D /usr/local/pgsql/data_coord1/' >>/usr/local/pgsql/data_coord1/logfile_coord 2>&1
su - postgres -c '/usr/local/pgsql/bin/pg_ctl -Z datanode start -D /usr/local/pgsql/data_datanode_1/' >>/usr/local/pgsql/data_datanode_1/logfile_datanode_1 2>&1
su - postgres -c '/usr/local/pgsql/bin/pg_ctl -Z datanode start -D /mnt/data_datanode_2/' >>/mnt/data_datanode_2/logfile_datanode_2 2>&1
su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm start -D /usr/local/pgsql/data_gtm/' >>/usr/local/pgsql/data_gtm/logfile_gtm 2>&1
exit 0
Для сервера №2 файл будет таким:
#! /bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
set -e
su - postgres -c '/usr/local/pgsql/bin/pg_ctl -Z coordinator start -D /usr/local/pgsql/data_coord/' >>/usr/local/pgsql/data_coord/logfile_coord 2>&1
su - postgres -c '/usr/local/pgsql/bin/pg_ctl -Z datanode start -D /usr/local/pgsql/data_datanode/' >>/usr/local/pgsql/data_datanode/logfile_datanode 2>&1
su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm start -D /usr/local/pgsql/data_gtm/' >>/usr/local/pgsql/data_gtm/logfile_gtm 2>&1
#su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm start -D /usr/local/pgsql/data_gtm/' >>/usr/local/pgsql/data_gtm/logfile_gtm 2>&1
exit 0
Перезагружаем сервис systemd:
# systemctl daemon-reload
Добавляем новый сервис в автозагрузку:
# systemctl enable postgres-xl-start
Теперь для старта сервиса (для старта всех узлов кластера на текущем сервере) теперь можно использовать команду:
# systemctl start postgres-xl-start

ПРИМЕЧАНИЕ.
Настроить корректный запуск резервного сервера GTM STANBY при старте системы не получилось.
После перезапуска серверов для запуска резервного GTM делаем на Сервере №2 для запуска GTM-STANBY
# su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm start -D /usr/local/pgsql/data_gtm/' >>/usr/local/pgsql/data_gtm/logfile_gtm 2>&1
Затем перегружаем основной GTM на Сервере №1
# su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm stop -D /usr/local/pgsql/data_gtm/'
# su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm start -D /usr/local/pgsql/data_gtm/' >>/usr/local/pgsql/data_gtm/logfile_gtm 2>&1

Проведем тестирование системы. Подключаемся к любому координатору и создадим пару таблиц. Одну с репликацией на все узлы Data Node, вторую с шардингом (распределением между узлами) и посмотрим как распределяются данные.
postgres=# CREATE TABLE log1 ( 
id SERIAL PRIMARY KEY, 
log_mess text,
log_date timestamp DEFAULT now()
) distribute by REPLICATION;
postgres=# CREATE TABLE log2 ( 
id SERIAL PRIMARY KEY, 
log_mess text,
log_date timestamp DEFAULT now()
) DISTRIBUTE BY HASH (id);
Заполним таблицы случайными числами:
INSERT INTO log1 (log_mess) SELECT s FROM generate_series(1, 100) s;
INSERT INTO log2 (log_mess) SELECT s FROM generate_series(1, 100) s;
Проанализируем выгрузку данных:
postgres=# explain analyze select count(*) from log1;
                                                 QUERY PLAN
-------------------------------------------------------------------------------------------------------------
 Remote Fast Query Execution  (cost=0.00..0.00 rows=0 width=0) (actual time=126.495..126.497 rows=1 loops=1)
   Node/s: datanode_3
 Planning time: 0.073 ms
 Execution time: 126.539 ms
(4 rows)

postgres=# explain analyze select count(*) from log2;
                                                                      QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=4.78..4.79 rows=1 width=0) (actual time=53.588..53.588 rows=1 loops=1)
   ->  Remote Subquery Scan on all (datanode_1,datanode_2,datanode_3)  (cost=0.00..4.42 rows=142 width=0) (actual time=52.319..53.393 rows=3 loops=1)
 Planning time: 15.856 ms
 Execution time: 66.150 ms
(4 rows)
Видим, что при запросе из таблицы log1 запрос идет только с одной ноды, так как данные везде одинаковы, а при запросе с log2 – со всех трех узлов, так как данные разделены по узлам.
Если подключится к узлу datanode_3 и запросить содержимое таблиц log1 и log2, то получим следующую картину:
$ psql -p 15432
postgres=# \d
             List of relations
 Schema |    Name     |   Type   |  Owner
--------+-------------+----------+----------
 public | log1        | table    | postgres
 public | log1_id_seq | sequence | postgres
 public | log2        | table    | postgres
 public | log2_id_seq | sequence | postgres
(4 rows)
postgres=# SELECT * FROM log1;
   id    | log_mess |          log_date
---------+----------+----------------------------
 2281101 | 1        | 2017-04-03 16:29:00.814566
 2281102 | 2        | 2017-04-03 16:29:00.814566
 2281103 | 3        | 2017-04-03 16:29:00.814566

2281199 | 99       | 2017-04-03 16:29:00.814566
 2281200 | 100      | 2017-04-03 16:29:00.814566
(100 rows)
postgres=# SELECT * FROM log2;
 id  | log_mess |          log_date
-----+----------+----------------------------
 262 | 8        | 2017-04-03 16:31:24.945303
 263 | 9        | 2017-04-03 16:31:24.945303
 267 | 13       | 2017-04-03 16:31:24.945303
 270 | 16       | 2017-04-03 16:31:24.945303
 271 | 17       | 2017-04-03 16:31:24.945303

350 | 96       | 2017-04-03 16:31:24.945303
 351 | 97       | 2017-04-03 16:31:24.945303
(40 rows)
Видим, что данные распределяются и реплицируются.


ПРИМЕЧАНИЕ 1:
При подключении к координатору у меня выводилось аварийное сообщение:
$ psql -p 5433
psql: FATAL:  Could not obtain a transaction ID from GTM. The GTM might have failed or lost connectivity
В логах координатора было множество сообщений:
ERROR:  Could not obtain a transaction ID from GTM. The GTM might have failed or lost connectivity
WARNING:  can not connect to GTM: В соединении отказано
WARNING:  can not connect to GTM: В соединении отказано
WARNING:  can not connect to GTM: В соединении отказано
Ошибка была в конфигурации серверов. Оказывается порт pooler_port у каждого узла кластера должен быть уникальным.

ПРИМЕЧАНИЕ 2:
Узел данных не позволит полностью очистить информацию, но ее можно перезаписать:
postgres=# alter node datanode1 WITH ( TYPE=datanode, HOST ='192.168.1.151', PORT=25432, PRIMARY=true);

ПРИМЕЧАНИЕ 3:
Можно создать таблицу, которая будет распределяться только на два узла данных:
CREATE TABLE test1
( id bigint NOT NULL, profile bigint NOT NULL,
  status integer NOT NULL, switch_date timestamp without time zone NOT NULL,
CONSTRAINT test1_id_pkey PRIMARY KEY (id)
) to node (datanode1, datanode2);

ПРИМЕЧАНИЕ 4:
Перевод с основного на резервный GTM
Остановили основной GTM, если он еще доступен
# su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm stop -D /usr/local/pgsql/data_gtm/'
Делаем резервный GTM основным
# nano /usr/local/pgsql/data_gtm/gtm.conf
Устанавливаем
startup = ACT
Запускаем его как основной
# su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm stop -D /usr/local/pgsql/data_gtm/'
# su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm start -D /usr/local/pgsql/data_gtm/' >>/usr/local/pgsql/data_gtm/logfile_gtm 2>&1
Устанавливаем переменную gtm_host с новым IP адресом GTM. У нас будет
gtm_host = '10.10.49.154' 
в следующих файлах:
Сервер №1
# nano /usr/local/pgsql/data_coord1/postgresql.conf
# nano /usr/local/pgsql/data_datanode_1/postgresql.conf
# nano /mnt/data_datanode_2/postgresql.conf
Сервере №2 
# nano /usr/local/pgsql/data_coord/postgresql.conf
# nano /usr/local/pgsql/data_datanode/postgresql.conf
Перезагружаем ноды, координаторы.
Сервер №1
# su - postgres -c 'pg_ctl stop -D /usr/local/pgsql/data_coord1 -Z coordinator'
# su - postgres -c 'pg_ctl stop -D /usr/local/pgsql/data_datanode_1 -Z datanode'
# su - postgres -c 'pg_ctl stop -D /mnt/data_datanode_2 -Z datanode'
# su - postgres -c 'pg_ctl start -D /usr/local/pgsql/data_coord1 -Z coordinator' >>/usr/local/pgsql/data_coord1/logfile_coord 2>&1
# su - postgres -c 'pg_ctl start -D /usr/local/pgsql/data_datanode_1 -Z datanode' >>/usr/local/pgsql/data_datanode_1/logfile_datanode_1 2>&1
# su - postgres -c 'pg_ctl start -D /mnt/data_datanode_2 -Z datanode' >>/mnt/data_datanode_2/logfile_datanode_2 2>&1
Сервер №2
# su - postgres -c 'pg_ctl stop -D /usr/local/pgsql/data_coord -Z coordinator' 
# su - postgres -c 'pg_ctl stop -D /usr/local/pgsql/data_datanode -Z datanode'
# su - postgres -c 'pg_ctl start -D /usr/local/pgsql/data_coord -Z coordinator' >>/usr/local/pgsql/data_coord/logfile_coord 2>&1
# su - postgres -c 'pg_ctl start -D /usr/local/pgsql/data_datanode -Z datanode' >>/usr/local/pgsql/data_datanode/logfile_datanode 2>&1
Затем снова перезапускаем основной GTM (на Сервере 2)
# su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm stop -D /usr/local/pgsql/data_gtm/'
# su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm start -D /usr/local/pgsql/data_gtm/' >>/usr/local/pgsql/data_gtm/logfile_gtm 2>&1
В файлах автозапуск на Сервере №1 комментируем строку
# nano /usr/bin/start_postgres_xl.sh
#su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm start -D /usr/local/pgsql/data_gtm/' >>/usr/local/pgsql/data_gtm/logfile_gtm 2>&1
В файле автозапуска на Сервере №2 эту же строку раскомментируем

ПРИМЕЧАНИЕ 5.
При необходимости перевести работу кластера на другой GTM необходимо:
1) Настроить будущий GTM, как GTM Standby
В файле конфигурации GTM (/usr/local/pgsql/data_gtm/gtm.conf) установить
startup = STANDBY 
и прописать настройки основного GTM, напрмимер:
active_host = '10.10.49.154' 
active_port = 6666   
2) Запустить будущий GTM, как GTM Standby.
# su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm start -D /usr/local/pgsql/data_gtm/' >>/usr/local/pgsql/data_gtm/logfile_gtm 2>&1
3) Перезапускаем основной GTM, так как он почему-то всегда валиться после запуска резервного
# su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm stop -D /usr/local/pgsql/data_gtm/'
# su - postgres -c '/usr/local/pgsql/bin/gtm_ctl -Z gtm start -D /usr/local/pgsql/data_gtm/' >>/usr/local/pgsql/data_gtm/logfile_gtm 2>&1
4) Дождаться, когда в логах GTM появится запись:
# tail  /usr/local/pgsql/data_gtm/gtm.log
26:1606874944:2017-04-15 14:53:37.152 MSK -LOG:  Copying node information from GTM active done.
LOCATION:  gtm_standby_restore_node, gtm_standby.c:231
27:1606874944:2017-04-15 14:53:37.152 MSK -LOG:  Restoring node information from the active-GTM succeeded.
LOCATION:  main, main.c:737
28:1606874944:2017-04-15 14:53:37.153 MSK -LOG:  Started to run as GTM-Standby.
LOCATION:  main, main.c:822
Значит синхронизация произошла.
5) Останавливаем основной GTM и делаем все так, как в ПРИМЕЧАНИИ №4



ССЫЛКИ
http://www.postgres-xl.org/ 
https://habrahabr.ru/post/253017/ 
https://habrahabr.ru/post/261457/ 
https://pgconf.ru/media2015c/sharp.pdf 
http://bonesmoses.org/2015/12/11/pg-phriday-postgres-xl-and-horizontal-scaling/