sql >> データベース >  >> RDS >> PostgreSQL

HAProxyとKeepalivedを使用したPostgreSQLの負荷分散

    プロキシレイヤーは、データベース層の可用性を高めるのに非常に役立ちます。データベースの障害やレプリケーショントポロジの変更を処理するために、アプリケーション側のコードの量を減らすことができます。このブログ投稿では、PostgreSQL上で動作するようにHAProxyを設定する方法について説明します。

    まず最初に-HAProxyはデータベースをネットワーク層プロキシとして機能します。基礎となる、時には複雑なトポロジーについての理解はありません。 HAProxyが行うのは、定義されたバックエンドにラウンドロビン方式でパケットを送信することだけです。パケットを検査せず、アプリケーションがPostgreSQLと通信するプロトコルを理解しません。その結果、HAProxyが単一のポートに読み取り/書き込み分割を実装する方法はありません。クエリの解析が必要になります。アプリケーションが書き込みから読み取りを分割し、それらを異なるIPまたはポートに送信できる限り、2つのバックエンドを使用してR/W分割を実装できます。それがどのように行われるかを見てみましょう。

    HAProxy構成

    以下に、HAProxyで構成された2つのPostgreSQLバックエンドの例を示します。

    listen  haproxy_10.0.0.101_3307_rw
            bind *:3307
            mode tcp
            timeout client  10800s
            timeout server  10800s
            tcp-check expect string master\ is\ running
            balance leastconn
            option tcp-check
            option allbackups
            default-server port 9201 inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100
            server 10.0.0.101 10.0.0.101:5432 check
            server 10.0.0.102 10.0.0.102:5432 check
            server 10.0.0.103 10.0.0.103:5432 check
    
    
    listen  haproxy_10.0.0.101_3308_ro
            bind *:3308
            mode tcp
            timeout client  10800s
            timeout server  10800s
            tcp-check expect string is\ running.
            balance leastconn
            option tcp-check
            option allbackups
            default-server port 9201 inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100
            server 10.0.0.101 10.0.0.101:5432 check
            server 10.0.0.102 10.0.0.102:5432 check
            server 10.0.0.103 10.0.0.103:5432 check

    ご覧のとおり、書き込みにはポート3307を使用し、読み取りには3308を使用します。このセットアップには、3つのサーバーがあります。1つはアクティブレプリカ、2つはスタンバイレプリカです。重要なのは、tcp-checkを使用してノードの状態を追跡することです。 HAProxyはポート9201に接続し、文字列が返されることを期待しています。バックエンドの正常なメンバーは期待されるコンテンツを返し、文字列を返さないメンバーは利用不可としてマークされます。

    Xinetdのセットアップ

    HAProxyがポート9201をチェックするとき、何かがそれをリッスンする必要があります。 xinetdを使用してそこでリッスンし、いくつかのスクリプトを実行できます。このようなサービスの構成例は次のようになります。

    # default: on
    # description: postgreschk
    service postgreschk
    {
            flags           = REUSE
            socket_type     = stream
            port            = 9201
            wait            = no
            user            = root
            server          = /usr/local/sbin/postgreschk
            log_on_failure  += USERID
            disable         = no
            #only_from       = 0.0.0.0/0
            only_from       = 0.0.0.0/0
            per_source      = UNLIMITED
    }

    次の行を追加する必要があります:

    postgreschk        9201/tcp

    / etc/servicesに。

    Xinetdはpostgreschkスクリプトを開始します。このスクリプトには、次のような内容が含まれています。

    #!/bin/bash
    #
    # This script checks if a PostgreSQL server is healthy running on localhost. It will
    # return:
    # "HTTP/1.x 200 OK\r" (if postgres is running smoothly)
    # - OR -
    # "HTTP/1.x 500 Internal Server Error\r" (else)
    #
    # The purpose of this script is make haproxy capable of monitoring PostgreSQL properly
    #
    
    export PGHOST='10.0.0.101'
    export PGUSER='someuser'
    export PGPASSWORD='somepassword'
    export PGPORT='5432'
    export PGDATABASE='postgres'
    export PGCONNECT_TIMEOUT=10
    
    FORCE_FAIL="/dev/shm/proxyoff"
    
    SLAVE_CHECK="SELECT pg_is_in_recovery()"
    WRITABLE_CHECK="SHOW transaction_read_only"
    
    return_ok()
    {
        echo -e "HTTP/1.1 200 OK\r\n"
        echo -e "Content-Type: text/html\r\n"
        if [ "$1x" == "masterx" ]; then
            echo -e "Content-Length: 56\r\n"
            echo -e "\r\n"
            echo -e "<html><body>PostgreSQL master is running.</body></html>\r\n"
        elif [ "$1x" == "slavex" ]; then
            echo -e "Content-Length: 55\r\n"
            echo -e "\r\n"
            echo -e "<html><body>PostgreSQL slave is running.</body></html>\r\n"
        else
            echo -e "Content-Length: 49\r\n"
            echo -e "\r\n"
            echo -e "<html><body>PostgreSQL is running.</body></html>\r\n"
        fi
        echo -e "\r\n"
    
        unset PGUSER
        unset PGPASSWORD
        exit 0
    }
    
    return_fail()
    {
        echo -e "HTTP/1.1 503 Service Unavailable\r\n"
        echo -e "Content-Type: text/html\r\n"
        echo -e "Content-Length: 48\r\n"
        echo -e "\r\n"
        echo -e "<html><body>PostgreSQL is *down*.</body></html>\r\n"
        echo -e "\r\n"
    
        unset PGUSER
        unset PGPASSWORD
        exit 1
    }
    
    if [ -f "$FORCE_FAIL" ]; then
        return_fail;
    fi
    
    # check if in recovery mode (that means it is a 'slave')
    SLAVE=$(psql -qt -c "$SLAVE_CHECK" 2>/dev/null)
    if [ $? -ne 0 ]; then
        return_fail;
    elif echo $SLAVE | egrep -i "(t|true|on|1)" 2>/dev/null >/dev/null; then
        return_ok "slave"
    fi
    
    # check if writable (then we consider it as a 'master')
    READONLY=$(psql -qt -c "$WRITABLE_CHECK" 2>/dev/null)
    if [ $? -ne 0 ]; then
        return_fail;
    elif echo $READONLY | egrep -i "(f|false|off|0)" 2>/dev/null >/dev/null; then
        return_ok "master"
    fi
    
    return_ok "none";

    スクリプトのロジックは次のようになります。ノードの状態を検出するために使用される2つのクエリがあります。

    SLAVE_CHECK="SELECT pg_is_in_recovery()"
    WRITABLE_CHECK="SHOW transaction_read_only"

    最初に、PostgreSQLが回復中であるかどうかを確認します。アクティブサーバーの場合は「false」、スタンバイサーバーの場合は「true」になります。 2つ目は、PostgreSQLが読み取り専用モードであるかどうかを確認します。アクティブサーバーは「オフ」を返し、スタンバイサーバーは「オン」を返します。結果に基づいて、スクリプトは正しいパラメーター(検出されたものに応じて、「master」または「slave」)を使用してreturn_ok()関数を呼び出します。クエリが失敗した場合、「return_fail」関数が実行されます。

    Return_ok関数は、渡された引数に基づいて文字列を返します。ホストがアクティブサーバーの場合、スクリプトは「PostgreSQLマスターが実行中です」を返します。スタンバイの場合、返される文字列は「PostgreSQLスレーブが実行中です」になります。状態が明確でない場合は、「PostgreSQLは実行中です」と返されます。ここでループが終了します。 HAProxyは、xinetdに接続して状態をチェックします。後者はスクリプトを開始し、HAProxyが解析する文字列を返します。

    覚えているかもしれませんが、HAProxyは次の文字列を想定しています:

    tcp-check expect string master\ is\ running

    書き込みバックエンドおよび

    tcp-check expect string is\ running.

    読み取り専用バックエンドの場合。これにより、アクティブサーバーが書き込みバックエンドで使用可能な唯一のホストになり、読み取りバックエンドではアクティブサーバーとスタンバイサーバーの両方を使用できます。

    ClusterControlのPostgreSQLとHAProxy

    上記の設定は複雑ではありませんが、設定には時間がかかります。 ClusterControlを使用して、これらすべてを設定できます。

    クラスタージョブのドロップダウンメニューには、ロードバランサーを追加するオプションがあります。次に、HAProxyをデプロイするオプションが表示されます。インストールする場所を入力し、いくつかの決定を行う必要があります。ホストで構成したリポジトリまたはソースコードからコンパイルされた最新バージョンからです。また、クラスター内のどのノードをHAProxyに追加するかを構成する必要があります。

    HAProxyインスタンスがデプロイされると、[ノード]タブでいくつかの統計にアクセスできます。

    ご覧のとおり、R / Wバックエンドの場合、1つのホスト(アクティブサーバー)のみがアップとしてマークされます。読み取り専用バックエンドの場合、すべてのノードが稼働しています。

    今日のホワイトペーパーをダウンロードするClusterControlを使用したPostgreSQLの管理と自動化PostgreSQLの導入、監視、管理、スケーリングを行うために知っておくべきことについて学ぶホワイトペーパーをダウンロードする

    キープアライブ

    HAProxyは、アプリケーションとデータベースインスタンスの間に位置するため、中心的な役割を果たします。残念ながら、単一障害点になる可能性もあります。障害が発生した場合、データベースへのルートはありません。このような状況を回避するために、複数のHAProxyインスタンスをデプロイできます。しかし、問題は、どのプロキシホストに接続するかをどのように決定するかです。 ClusterControlからHAProxyをデプロイした場合は、別の「ロードバランサーの追加」ジョブを実行するのと同じくらい簡単です。今回はKeepalivedをデプロイします。

    上のスクリーンショットでわかるように、最大​​3つのHAProxyホストを選択でき、Keepalivedがそれらの上にデプロイされ、それらの状態を監視します。そのうちの1つに仮想IP(VIP)が割り当てられます。アプリケーションは、このVIPを使用してデータベースに接続する必要があります。 「アクティブな」HAProxyが使用できなくなると、VIPは別のホストに移動されます。

    これまで見てきたように、PostgreSQL用の完全な高可用性スタックをデプロイするのは非常に簡単です。試してみて、フィードバックがあればお知らせください。


    1. ページングを実装する効率的な方法

    2. DDLステートメントは常に暗黙のコミットを提供しますか、それとも暗黙のロールバックを取得できますか?

    3. Oracleでテーブル、ビュー、シノニムのすべてのインデックスとその列を検索する方法

    4. 高可用性のためのMariaDBレプリケーションのデプロイ