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

PostgreSQLのロードバランサーの比較

    負荷分散により、特にアプリケーションの観点からシステムパフォーマンスが向上し、複数のコンピューターが同じデータを提供できるようになります。これは、データベースの変更をマスターノードのみにルーティングしながら、負荷がクライアントクエリ間でプライマリノードまたはマスターノード以外のレプリカノードに分散されるように機能します。その後、マスターノードへの変更は、PostgreSQLストリーミングレプリケーションを使用して各レプリカに伝播されます。

    ロードバランサーはPostgreSQLにどのように影響しますか?

    負荷分散を利用すると、クライアントアプリケーションが負荷分散サーバーに接続するように指示され、クエリ要求のタイプに応じて、開始された接続が使用可能なPostgreSQLノードに分散されます。これは、特定のPostgreSQLサーバーの未処理の負荷にストレスをかけるのに役立ち、クラスター内の使用可能なノード間の負荷の並列バランスを促進します。

    PostgreSQLを使用すると、これを機能させるための既存のソリューションがすでにいくつかあります。これらのソリューションはシームレスに機能するか、負荷分散は現在のトポロジ(プライマリノードとスタンバイノード)で機能しますが、負荷分散はアプリケーション層自体に実装されます。負荷分散は、サーバーが連携する際の根本的な問題である同期の問題という課題に直面しています。すべてのユースケースで同期の問題の影響を排除する単一のソリューションはないため、複数のソリューションがあります。各ソリューションは、この問題に異なる方法で対処し、特定のワークロードへの影響を最小限に抑えます。

    このブログでは、これらのロードバランサーを比較し、PostgreSQLワークロードにとってどれほど有益であるかを見ていきます。

    PostgreSQLのHAProxyロードバランシング

    HAProxyは、プロキシと非常に高速なI / Oレイヤー、および優先度ベースのマルチスレッドスケジューラを組み合わせたイベント駆動型の非ブロッキングエンジンです。データ転送の目標を念頭に置いて設計されているため、そのアーキテクチャは、最小限の操作でデータを可能な限り高速に移動するように最適化された軽量プロセスで動作するように設計されています。これは、接続をできるだけ長く同じCPUに固定することにより、CPUキャッシュ効率を最適化することに重点を置いています。そのため、各レベルでバイパスメカニズムを提供する階層化モデルを実装し、必要な場合を除いてデータがより高いレベルに到達しないようにします。ほとんどの処理はカーネルで実行されます。 HAProxyは、いくつかのヒントを与えるか、後でグループ化できると推測したときに特定の操作を回避することによって、カーネルが可能な限り高速に作業できるように最善を尽くします。その結果、一般的な数値は、HAProxyで費やされた処理時間の15%に対してTCPまたはHTTPクローズモードのカーネルで85%、HAProxyで約30%、HTTPキープアライブモードのカーネルで70%を示しています。

    HAProxyには、負荷分散の追加機能もあります。たとえば、TCPプロキシ機能を使用すると、組み込みのチェックサービスサポートを使用して、データベース接続、特にPostgreSQLでTCPプロキシ機能を使用できます。データベースサービスのサポートはありますが、特にレプリケーションタイプのクラスターの場合、必要なヘルスチェックでは不十分です。本番環境にデプロイする際の標準的なアプローチは、TCPチェックを使用してから、HAProxyを使用してxinetdに依存することです。

    PostgreSQLにHAProxyを使用する利点

    HAProxyの最も優れている点は、軽量で構成と使用が簡単で、期待どおりに機能することです。 PostgreSQLクラスター上でのHAProxyの使用は、大規模な組織からさまざまなSME / SMBに複数回実装および展開されており、本番環境で使用されています。データベースだけでなく、Webアプリケーションやジオロードバランシング(複数のデータセンターにトラフィックを分散する)などの他のネットワークサービスでも、本番環境と高いワークロード容量で長い間証明されています。 PostgreSQL上にHAProxyを搭載することで、ユーザーは応答を抑制または制限して、クラスター内の使用可能なすべてのノードに負荷を適切に並列化および分散することができます。 HAProxyに組み込まれたメカニズムにより、ユーザーは高可用性をシームレスにセットアップし、負荷が必要な場合に簡単に拡張でき、単一障害点(SPOF)を回避できます。

    PostgreSQLにHAProxyを使用する場合の短所

    HAProxyは、クエリフィルタリングを提供せず、要求されているステートメントのタイプを識別するためのクエリ分析も提供しません。単一のポートで読み取り/書き込み分割を実行する機能がありません。 HAProxyの上にロードバランサーを設定するには、少なくとも書き込み用に異なるポートを設定し、読み取り用に異なるポートを設定する必要があります。これには、ニーズに合わせてアプリケーションを変更する必要があります。

    HAProxyは、ヘルスチェックのためにPostgreSQLで非常に単純な機能サポートも行いますが、これは、ノードにpingを実行してバウンスバック応答を待つかのように、ノードが稼働しているかどうかを判断するだけです。要求された接続をクライアントから目的のノードに転送しようとしているノードの役割は識別されません。したがって、レプリケーショントポロジを理解するためのHAProxyの機能を理解していないか、機能がありません。ただし、ユーザーは異なるポートに基づいて個別のリスナーを作成できますが、それでも負荷分散のニーズを満たすためにアプリケーション内に変更を追加します。これは、xinetdで外部スクリプトを使用することで、要件を満たすための回避策になる可能性があることを意味します。それでも、HAProxyに統合されておらず、人為的エラーが発生する可能性があります。

    1つのノードまたはノードのグループをメンテナンスモードにする必要がある場合は、HAProxyにも変更を適用する必要があります。そうしないと、壊滅的となる可能性があります。

    PostgreSQLの負荷分散のためのPgpool-II

    Pgpool-IIはオープンソースソフトウェアであり、負荷分散を実装し、これを使用してアプリケーションからプロキシレイヤーまでミドルウェアとして機能し、負荷を分散するために、大規模なPostgreSQLコミュニティに採用されています。クエリまたはデータベース接続ごとのリクエストのタイプを完全に分析した後。 Pgpool-IIは、元々Pgpoolと名付けられていた2003年から、2006年にPgpool-IIになるまで、非常に長い間存在してきました。これは、負荷分散だけでなく、多くの優れた機能のための非常に安定したプロキシツールの証でもあります。 。

    Pgpool-IIは、PostgreSQLのスイスアーミーナイフとして知られており、PostgreSQLサーバーとPostgreSQLデータベースクライアントの間に配置されるプロキシソフトウェアです。 PgPool-IIの基本的な考え方は、クライアント上に配置され、読み取りクエリをスタンバイノードに配信する必要がある一方で、書き込みまたは変更はプライマリに直接送信されるというものです。これは、負荷分散を行うだけでなく、高可用性をサポートし、接続プーリングを提供する非常にインテリジェントな負荷分散ソリューションです。インテリジェントなメカニズムにより、マスターとスレーブ間の負荷のバランスをとることができます。したがって、書き込みはマスターにロードされ、読み取りの処理は、ホットスタンバイノードと思われる使用可能な読み取り専用サーバーに送信されます。 Pgpool-IIは、論理レプリケーションも提供します。 PostgreSQLサーバー側で組み込みのレプリケーションオプションが改善されたため、その使用と重要性は低下しましたが、これは古いバージョンのPostgreSQLにとって依然として価値のあるオプションです。これらすべてに加えて、接続プールも提供します。

    Pgpool-IIは、すべての機能をサポートするために、PgBouncerよりも複雑なアーキテクチャを備えています。どちらも接続プールをサポートしているため、後者には負荷分散機能がありません。

    Pgpool-IIは複数のPostgreSQLサーバーを管理できます。レプリケーション機能を利用することで、2台以上の物理ディスク上にリアルタイムバックアップを作成できるため、ディスク障害が発生した場合でもサーバーを停止することなくサービスを継続できます。 Pgpool-IIは接続プールにも対応しているため、超過接続を制限できます。 PostgreSQLとの同時接続の最大数には制限があり、この数の接続の後で接続は拒否されます。ただし、接続の最大数を設定すると、リソース消費が増加し、システムパフォーマンスに影響します。 pgpool-IIにも接続の最大数に制限がありますが、エラーをすぐに返すのではなく、追加の接続がキューに入れられます。

    負荷分散では、データベースが複製されている場合、任意のサーバーでSELECTクエリを実行すると同じ結果が返されます。 pgpool-IIは、レプリケーション機能を利用して、SELECTクエリを複数のサーバーに分散することで各PostgreSQLサーバーの負荷を軽減し、システム全体のスループットを向上させます。せいぜい、パフォーマンスはPostgreSQLサーバーの数に比例して向上します。負荷分散は、多数のユーザーが同時に多くのクエリを実行している状況で最適に機能します。

    並列クエリ機能を使用すると、データを複数のサーバー間で分割できるため、すべてのサーバーでクエリを同時に実行して、全体の実行時間を短縮できます。並列クエリは、大規模なデータを検索する場合に最適です。

    PostgreSQLにPgpoolを使用するメリット

    これは、負荷分散だけでなく、機能が豊富なタイプのソフトウェアです。このツールのコア機能とサポートは非​​常にオンデマンドであり、接続プール、代替のgo PgBouncer、ネイティブレプリケーション、オンラインリカバリ、メモリ内クエリキャッシュ、自動フェイルオーバー、ウォッチドッグを使用したサブプロセスによる高可用性を提供します。このツールは非常に古く、PostgreSQLコミュニティによって継続的に大規模にサポートされているため、問題に対処するのは難しいことではありません。ドキュメントは、質問を探すときにここでの友達ですが、コミュニティでヘルプを検索することは難しくありません。このツールはオープンソースであるため、BSDライセンスに準拠している限り自由に使用できます。

    Pgpool-IIにはSQLパーサーもあります。これは、SQLを正確に解析し、クエリを書き直すことができることを意味します。これにより、Pgpool-IIは、クエリ要求に応じて並列処理を強化できます。

    PostgreSQLにPgpoolを使用することの短所

    Pgpool-IIは、ノードフェンシングメカニズムを提供するSTONITH(ヘッド内の他のノードを撃つ)を提供していません。 PostgreSQLサーバーに障害が発生した場合、サービスの可用性が維持されます。 Pgpool-IIは、単一障害点(SPOF)になることもあります。ノードがダウンすると、データベースの接続性と可用性はその時点から停止します。これは、Pgpool-IIとの冗長性を確保し、ウォッチドッグを使用して複数のPgpool-IIノードを調整する必要があることで修正できますが、追加の作業が追加されます。

    接続プールの場合、残念ながら、接続プールのみに焦点を当てている場合、特に少数のクライアントの場合、Pgpool-IIがあまりうまく機能しないのは接続プールです。各子プロセスには独自のプールがあり、どのクライアントがどの子プロセスに接続するかを制御する方法がないため、接続の再利用に関しては運が悪すぎます。

    PostgreSQLの負荷分散にJDBCドライバーを使用する

    Java Database Connectivity(JDBC)は、プログラミング言語Java用のアプリケーションプログラミングインターフェイス(API)であり、クライアントがデータベースにアクセスする方法を定義します。これはJavaStandardEditionプラットフォームの一部であり、データベース内のデータをクエリおよび更新するためのメソッドを提供し、リレーショナルデータベースを対象としています。

    PostgreSQL JDBCドライバー(略してPgJDBC)を使用すると、Javaプログラムは、データベースに依存しない標準のJavaコードを使用してPostgreSQLデータベースに接続できます。 Pure Java(Type 4)で記述されたオープンソースのJDBCドライバーであり、PostgreSQLネイティブネットワークプロトコルで通信します。このため、ドライバーはプラットフォームに依存しません。コンパイルすると、ドライバーはどのシステムでも使用できます。

    これは、以前に指摘した負荷分散ソリューションとは比較できません。したがって、このツールはアプリケーションプログラミングインターフェイスAPIであり、JDBCをサポートする、または少なくともJDBCに接続するためのアダプタを備えた、記述されているプログラミング言語のタイプに関係なく、アプリケーションから接続できます。一方、Javaアプリケーションの方が有利です。

    JDBCを使用した負荷分散は非常に単純ですが、その役割を果たします。このツールが提供する必要のある負荷分散メカニズムをトリガーできる接続パラメーターが提供されます。

    • targetServerType-PostgreSQLサーバーの定義要素に従って、必要な状態/役割を持つサーバーのみへの接続を開くことができます。許可される値は、any、primary、master(非推奨)、slave(非推奨)、secondary、preferSlave、preferSecondaryです。状態または役割は、サーバーが書き込みを許可するかどうかを監視することによって決定されます。
    • hostRecheckSeconds-ホストの状態に関する知識がJVM全体のグローバルキャッシュにキャッシュされる時間を秒単位で制御します。デフォルト値は10秒です。
    • loadBalanceHosts –最初のホストが常に試行されるか(falseに設定されている場合)、または接続がランダムに選択されるか(trueに設定されている場合)を構成できます

    したがって、ブール値を受け入れるloadBalanceHostsを使用します。 loadBalanceHostsはデフォルトモードでは無効になっており、ホストは指定された順序で接続されます。有効なホストが適切な候補のセットからランダムに選択された場合。 jdbcを使用してデータベースに接続する場合の基本的な構文は次のとおりです。

    • jdbc:postgresql:database
    • jdbc:postgresql:/
    • jdbc:postgresql:// host / database
    • jdbc:postgresql:// host /
    • jdbc:postgresql:// host:port / database
    • jdbc:postgresql:// host:port /

    loadBalanceHostsと接続が、以下のように構成された複数のホストを受信するとします。

    jdbc:postgresql://host1:port1,host2:port2,host3:port3/database

    これにより、JDBCは適切な候補のセットからランダムに選択できます。

    PostgreSQLにPgJDBCを使用するメリット

    ロードバランサーとしてミドルウェアやプロキシを必要としません。このプロセスでは、通過するリクエストごとに追加のレイヤーがないため、アプリケーションフロントエンドのパフォーマンスがさらに向上します。アプリケーションの準備ができていて、JDBCとのインターフェースをサポートするように作成されている場合、これは有利であり、特に予算が厳しく、その唯一の目的と機能専用のプロセスのみを制限したい場合は、ミドルウェアを増やす必要はありません。トラフィックが多く需要の多いアプリケーションとは異なり、ロードバランサーとして機能するプロキシサーバーが必要になる場合があり、接続の高い要求を適切に処理するために追加のリソースが必要になる場合があります。これには、CPUとメモリ処理の需要も必要です。

    PostgreSQLにPgJDBCを使用する場合の短所

    要求されるすべての接続に対してコードを設定する必要があります。これはアプリケーションプログラミングインターフェイスです。つまり、アプリケーションが適切なサーバーに送信する各要求を非常に要求している場合は特に、対処するための作業が遅れています。高可用性や自動スケーラビリティはなく、単一障害点があります。

    PostgreSQLの負荷分散のためにlibpqで実装されたラッパーまたはツールはどうですか?

    libpqは、CアプリケーションプログラマーのPostgreSQLへのインターフェースです。 libpqは、クライアントプログラムがPostgreSQLバックエンドサーバーにクエリを渡し、これらのクエリの結果を受信できるようにするライブラリ関数のセットです。

    libpqは、C ++、PHP、Perl、Python、Tcl、Swift、ECPG向けに作成されたものなど、他のいくつかのPostgreSQLアプリケーションインターフェイスの基盤となるエンジンでもあります。したがって、これらのパッケージの1つを使用する場合、libpqの動作のいくつかの側面が重要になります。

    libpqは負荷分散を自動化しないため、負荷分散ソリューションのツールとは見なされません。ただし、接続用にリストされている前のサーバーに障害が発生した場合は、次に使用可能なサーバーに接続できます。たとえば、使用可能なホットスタンバイノードが2つある場合、最初のノードがビジー状態で対応するタイムアウト値に応答しない場合、指定された接続で次に使用可能なノードに接続します。指定したセッション属性のタイプに依存します。これは、パラメーターtarget_session_attrsに依存します。

    パラメーターtarget_session_attrsは、読み取りと書き込みの値、および指定されていない場合はデフォルト値である値を受け入れます。パラメータtarget_session_attrsは、読み取り/書き込みに設定されている場合、接続中に読み取り/書き込みトランザクションが受け入れられる接続のみを実行します。クエリSHOWtransaction_read_onlyは、接続が成功すると送信されます。結果がオンの場合、接続は閉じられます。つまり、ノードはレプリカとして識別されるか、書き込みを処理しません。接続文字列に複数のホストが指定されている場合、接続の試行が失敗したかのように、残りのサーバーが試行されます。このパラメーターのデフォルト値anyは、すべての接続が受け入れ可能であることを意味します。 target_session_attrsに依存するだけでは負荷分散には不十分ですが、ラウンドロビン方式をシミュレートできる場合があります。 libpqを使用した以下のCコードの例を参照してください

    #include <stdio.h>
    
    #include <stdlib.h>
    
    #include <string.h>
    
    #include <time.h>
    
    #include <unistd.h>
    
    #include <libpq-fe.h>
    
    
    
    
    const char* _getRoundRobinConn() {
    
       char* h[2];
    
       h[0] = "dbname=node40 host=192.168.30.40,192.168.30.50";
    
       h[1] = "dbname=node50 host=192.168.30.50,192.168.30.40";
    
    
    
       time_t t;
    
       //srand((unsigned)time(&t));
    
       sleep(1.85);
    
       srand((unsigned)time(NULL));
    
    
    
       return h[rand() % 2];
    
    }
    
    
    
    void
    
    _connect()
    
    {
    
      PGconn *conn;
    
      PGresult *res;
    
      char strConn[120];
    
    
    
    
      snprintf(strConn, 1000, "user=dbapgadmin password=dbapgadmin %s target_session_attrs=any", _getRoundRobinConn());
    
      //printf("\nstrConn value is: %s\n", strConn);
    
    
    
      conn = PQconnectdb(strConn);
    
    
    
      res = PQexec(conn, "SELECT current_database(), inet_client_addr();");
    
    
    
      if ( PQresultStatus(res)==PGRES_TUPLES_OK )
    
      {
    
        printf("current_database = %s on %s\n", PQgetvalue(res, 0, 0),
    
    PQhost(conn));
    
      } else {
    
    
    
        printf("\nFailed... Message Code is: %d\n", PQresultStatus(res));
    
      }
    
    
    
      PQclear(res);
    
      PQfinish(conn);
    
    
    
    }
    
    
    
    int main(void)
    
    {
    
      int i;
    
      for (i=0 ; i<5 ; i++)
    
        _connect();
    
    
    
      return 0;
    
    }
    結果が明らかになります

    [email protected]:/home/vagrant# gcc -I/usr/include/postgresql -L/usr/lib/postgresql/12/lib libpq_conn.c -lpq -o libpq_conn; ./libpq_conn
    
    current_database = node40 on 192.168.30.40
    
    current_database = node40 on 192.168.30.40
    
    current_database = node50 on 192.168.30.50
    
    current_database = node40 on 192.168.30.40
    
    current_database = node50 on 192.168.30.50

    ノード.40(プライマリノード)がダウンした場合、target_session_attrs値がいずれかである限り、接続は常に.50に転送されることに注意してください。

    その場合、libpqを使用して自由に独自のものを作成できます。 libpqやそのラッパーに依存するプロセスはあまりにも生々しく、これが目的の負荷分散メカニズムを提供し、ノードに均等に分散できるとは言えません。確かに、このアプローチとコーディングは改善できますが、これは無料でオープンソースであり、ミドルウェアに依存せずにコーディングでき、負荷分散の仕組みを自由に設計できると考えられています。

    PostgresQLにlibpqを使用するメリット

    libpqライブラリは、Cプログラミング言語で構築されたプログラマーのアプリケーションインターフェイスです。それでも、ライブラリはラッパーとしてさまざまな言語で実装されているため、プログラマーはお気に入りの言語を使用してPostgreSQLデータベースと通信できます。お気に入りの言語を使用して独自のアプリケーションを直接作成し、クエリを送信する予定のサーバーを一覧表示できますが、障害またはタイムアウトが発生した場合は、負荷を分散する予定の使用可能なノードに負荷を送信します。 Python、Perl、PHP、Ruby、Tcl、Rustなどの言語で利用できます。

    PostgresQLにlibpqを使用することの短所

    負荷並列処理の実装は完全ではなく、コードによって独自の負荷分散メカニズムを作成する必要があります。 target_session_attrs paramを使用したPostgreSQLデータベースへのプログラミングインターフェイスはすべて単独であるため、使用またはカスタマイズできる構成はありません。つまり、データベース接続を作成するときは、レプリカ/スタンバイノードに接続する一連の読み取り接続を用意してから、アプリケーション内にあるか作成する必要があるかに関係なく、コード内のライターまたはプライマリノードに送信するクエリを作成する必要があります。負荷分散ソリューションを管理するための独自のAPI。

    このアプローチを使用する場合、フロントエンドアプリケーションの観点からミドルウェアをバックエンドとしてデータベースに使用する必要はありません。もちろんこれは軽量ですが、接続時にサーバーのリストを送信する場合、このアプローチのコードを追加する必要がない限り、負荷が理解されて均等に送信されることを意味するわけではありません。これは面倒な作業を追加するだけですが、既存のソリューションが存在するのに、なぜ車輪の再発明が必要なのですか?

    結論

    PostgreSQLでロードバランサーを実装するのは難しい場合がありますが、処理するアプリケーションの種類とコストによって異なります。負荷が高い場合は、負荷を適切に分散し、ノードの状態や状態を監視するために、プロキシとして機能するミドルウェアが必要になることがあります。一方、専用サーバーで実行する必要があるか、ニーズを満たすために追加のCPUとメモリを必要とするサーバーリソースが必要になる場合があり、これによりコストが増加します。したがって、時間のかかる簡単な方法もありますが、すでに使用可能なサーバーに負荷を分散できます。ただし、プログラミングスキルとAPIの機能の理解が必要です。


    1. OracleクエリでXMLTypeノードを連結します

    2. 古い認証を使用してMySQL4.1以降に接続できません

    3. SQLServer全文検索を使用して製品分析を実行する方法を学びます。パート2

    4. EntityFramework6トランザクションのロールバック