データベースのパフォーマンスは、データベースクラスターを維持する場合、特に時間の経過とともに大きくなるため、非常に重要な問題です。これは、アプリケーションがトラフィックが少ない状態で開始され、その後、中程度または重い読み取り/書き込みワークロードに成長する場合に特に当てはまります。
覚えておくべきことは、特定のワークロードは時間の経過とともに変化する可能性があるため、長期間信頼できる完全な構成はないということです。
ClusterControlを使用して、新しいPostgreSQLデータベースクラスターを作成またはデプロイすると、ハードウェアリソースのチェックなどの基本的な分析が実行され、自動調整が適用され、選択した調整可能なパラメーターの値が設定されます。 PostgreSQLが進化するにつれて、特に負荷分散のために、さまざまな構成をサポートするための多くのツールも開発されてきました。
このブログでは、HAProxyの重要性と、HAProxyがパフォーマンスの向上にどのように役立つかを見ていきます。これは古いツールですが、データベースサーバーだけでなく、ネットワークアプリケーション固有のプロトコルもサポートする強力なプロキシやロードバランサーです。 HAProxyは、構成に基づくセットアップのタイプに応じて、それぞれレイヤー4とレイヤー7を介して動作できます。
PostgreSQLパフォーマンスチューニング
PostgreSQLのパフォーマンスを向上させる主な要因の1つは、initdbからランタイムパラメーター値への基本的なパラメーター調整から始まります。これは、特定の要件に従って、必要なワークロードを処理できる必要があります。 PostgreSQLのHAProxy機能を利用する前に、データベースサーバーが安定していて、目的の変数に調整されている必要があります。データベースサーバーのパフォーマンスドライブに影響を与える可能性のあるものについて、PostgreSQLの領域のリストを見てみましょう。
PostgreSQLは効率的であり、わずか256Mbのメモリで効果的に実行できます。メモリは高価ではありませんが、ほとんどのデータセットは4Gib未満です。少なくとも4Gibがある場合、アクティブなデータセットをファイルやshared_bufferキャッシュに残すことができます。
メモリ管理のためにPostgreSQLを調整することは、設定する必要のある最も主要で基本的なことの1つです。適切に設定すると、データベースサーバーのパフォーマンスの向上に影響を与える可能性があります。遊んでいるテーブルの種類にもよりますが。クエリやテーブル定義が不適切な場合も、パフォーマンスが低下する可能性があります。テーブルに適切なインデックスが定義されていて、インデックスを参照するクエリを使用すると、80%から100%のクエリをメモリから取得できる可能性があります。これは特に、インデックスバッファに、テーブルで定義されたインデックスをロードするための適切な値がある場合です。パフォーマンス向上のために一般的に設定されるパラメータを見てみましょう。
- shared_buffers -PostgreSQLは、shared_buffersを使用してメインメモリスペースのサイズを決定します。 PostgreSQL内のすべてのホットタプル(およびインデックスエントリ)の作業キャッシュ。このパラメータは、データベースサーバーが共有メモリバッファに使用するメモリの量を設定します。これは事前に割り当てられたキャッシュ(バッファ)です。 Linuxベースのシステムの場合、/ etc/sysctl.confカーネル構成ファイルを介して永続的に設定できるカーネルパラメーターkernel.shmmaxを設定するのが理想的です。
- temp_buffers -各セッションで使用される一時バッファの最大数を設定します。これらは、一時テーブルにアクセスするためにのみ使用されるローカルセッションバッファです。セッションは、temp_buffersで指定された制限まで、必要に応じて一時バッファを割り当てます。
- work_mem -PostgreSQLがスワップする前に、作業操作(ソート)に使用できる作業メモリー。グローバルに設定しないでください(postgresql.conf)。トランザクションごとに使用します。これは、クエリごと、接続ごと、または並べ替えごとに不適切な場合があるためです。 EXPLAIN ANALYZEを使用して、オーバーフローしているかどうかを確認することをお勧めします。
- maintenance_work_mem -メンテナンス操作(VACUUM、CREATE INDEX、ALTERTABLE…ADDFOREIGN KEY…)に使用するメモリの量を指定します
- temp_file_limit -セッションが一時ファイル(ソートやハッシュの一時ファイルなど)、または保持カーソルのストレージファイルに使用できるディスク容量の最大量を指定します。この制限を超えようとするトランザクションはキャンセルされます。
- fsync- fsyncが有効になっている場合、PostgreSQLは更新が物理的にディスクに書き込まれていることを確認しようとします。これにより、オペレーティングシステムまたはハードウェアがクラッシュした後、データベースクラスターを一貫した状態に回復できます。通常、fsyncを無効にするとパフォーマンスが向上しますが、電源障害やシステムクラッシュが発生した場合にデータが失われる可能性があります。したがって、外部データからデータベース全体を簡単に再作成できる場合にのみ、fsyncを非アクティブ化することをお勧めします。
- synchronous_commit -コミットがWALがディスクに書き込まれるのを待ってから、成功ステータスをクライアントに返すように強制するために使用されます。この変数には、パフォーマンスと信頼性の間のトレードオフがあります。より高いパフォーマンスが必要な場合は、これをオフに設定します。これは、サーバーがクラッシュしたときにデータが失われる傾向があることを意味します。それ以外の場合、信頼性が重要な場合は、これをオンに設定します。これは、成功ステータスとディスクへの書き込みの保証との間に時間差があることを意味し、パフォーマンスに影響を与える可能性があります。
- checkpoint_timeout、checkpoint_completion_target -PostgreSQLは変更をWALに書き込みますが、これはコストのかかる操作です。変更をWALに頻繁に書き込む場合は、パフォーマンスに悪影響を与える可能性があります。したがって、どのように機能するか、チェックポイントプロセスはデータをデータファイルにフラッシュします。このアクティビティは、チェックポイントが発生したときに実行され、大量のIOを引き起こす可能性があります。このプロセス全体には、コストのかかるディスクの読み取り/書き込み操作が含まれます。あなた(管理者ユーザー)は、必要と思われるときはいつでもCHECKPOINTを発行するか、これらのパラメーターに必要な値を設定することによってそれを自動化することができます。 checkpoint_timeoutパラメーターは、WALチェックポイント間の時間を設定するために使用されます。これを低く設定しすぎると、ディスクに書き込まれるデータが増えるため、クラッシュリカバリ時間が短縮されますが、すべてのチェックポイントが貴重なシステムリソースを消費するため、パフォーマンスも低下します。 checkpoint_completion_targetは、チェックポイントが完了するまでのチェックポイント間の時間の割合です。チェックポイントの頻度が高いと、パフォーマンスに影響を与える可能性があります。チェックポイントをスムーズにするには、checkpoint_timeoutを低い値にする必要があります。そうしないと、OSは、比率が満たされるまですべてのダーティページを蓄積し、その後、大きなフラッシュを実行します。
PostgreSQLのパフォーマンスを向上させる特定のパラメータがあります。これらを以下にリストしましょう:
- wal_buffers -PostgreSQLはWAL(ログ先行書き込み)レコードをバッファーに書き込み、これらのバッファーはディスクにフラッシュされます。 wal_buffersで定義されるバッファのデフォルトサイズは16MBですが、同時接続が多い場合は、値を大きくするとパフォーマンスが向上します。
- effective_cache_size -effective_cache_sizeは、ディスクキャッシングに使用できるメモリの見積もりを提供します。これは単なるガイドラインであり、正確に割り当てられたメモリやキャッシュサイズではありません。実際のメモリは割り当てられませんが、カーネルで使用可能なキャッシュの量をオプティマイザに通知します。この値の設定が低すぎると、クエリプランナーは、有用であっても、一部のインデックスを使用しないことを決定できます。したがって、大きな値を設定することは常に有益です。
- default_statistics_target -PostgreSQLは、データベース内の各テーブルから統計を収集して、クエリがそれらに対してどのように実行されるかを決定します。デフォルトでは、あまり多くの情報を収集しません。適切な実行計画が得られない場合は、この値を増やしてから、データベースでANALYZEを再度実行する必要があります(またはAUTOVACUUMを待ちます)。
PostgreSQLクエリの効率
PostgreSQLには、クエリを最適化するための非常に強力な機能があります。組み込みのGeneticQueryOptimizer(GEQOとして知られています)を使用します。ランダム検索によるヒューリスティック最適化手法である遺伝的アルゴリズムを使用しています。これは、非常に優れたパフォーマンス最適化を提供するJOINを使用して最適化を実行するときに適用されます。結合計画の各候補は、基本関係に結合するシーケンスによって表されます。それは、いくつかの可能な結合シーケンスをランダムに生成することによって、ランダムに遺伝的関係を実行します。
考慮される結合シーケンスごとに、標準のプランナーコードが呼び出され、その結合シーケンスを使用してクエリを実行するコストが見積もられます。したがって、JOINシーケンスごとに、すべてに最初に決定された関係スキャン計画があります。次に、クエリプランは、最も実行可能でパフォーマンスの高いプランを計算します。つまり、推定コストが低く、コストが高いプランよりも「適合性が高い」と見なされます。
PostgreSQLに統合された強力な機能と、必要な要件に応じて適切に構成されたパラメーターを備えているため、負荷がプライマリノード。 HAProxyを使用した負荷分散は、PostgreSQLのドライブパフォーマンスをさらに向上させるのに役立ちます。
PostgreSQLサーバーノードを処理するパフォーマンスは優れているかもしれませんが、特にトラフィックが多く、需要が境界を超えた場合に、どのような種類のワークロードが発生するかを予測できない場合があります。プライマリとセカンダリの間で負荷のバランスをとることで、PostgreSQLデータベースクラスタに接続しているアプリケーションやクライアント内のパフォーマンスが向上します。これをどのように行うことができるかは、負荷の分散と高負荷処理によるプライマリノードの停止を回避するための高可用性と冗長性のための非常に一般的なセットアップであるため、もはや問題ではありません。
HAProxyを使用したセットアップは簡単です。それでも、ClusterControlを使用すると、より効率的に高速で実行可能になります。そこで、ClusterControlを使用してこれを設定します。
HAProxyを使用したPostgreSQLのセットアップ
これを行うには、PostgreSQLクラスターの上にHAProxyをインストールしてセットアップする必要があります。 HAProxyには、オプションpgsql-checkを介してPostgreSQLをサポートする機能がありますが、そのサポートは、ノードが稼働しているかどうかを判断するための非常に単純な実装です。プライマリノードとリカバリノードを識別するためのチェックはありません。オプションは、PostgreSQLクラスター内の特定のノードの状態をチェックするxinetdサービスを介してリッスンするためにHAProxyとの通信に依存するxinetdを使用することです。
ClusterControlの下で、以下のように[管理]→[ロードバランサー]に移動します
次に、下のスクリーンショットのUIに基づいてフォローします。 [詳細設定を表示]をクリックして、より詳細なオプションを表示できます。ただし、UIに従うのは非常に簡単です。以下を参照してください
冗長性のない単一ノードのHAProxyのみをインポートしていますが、このブログでは、もっと簡単にしましょう。
上記のように、192.168.30.20と192.168.30.30がプライマリですそれぞれセカンダリ/リカバリノード。一方、HAProxyはセカンダリ/リカバリノードにインストールされます。理想的には、HAProxyを複数のノードにインストールして、冗長性と高可用性を高めることができます。データベースノードからHAProxyを分離するのが最善です。予算が限られている場合や使用量を節約している場合は、データベースノードもインストールされているHAProxyノードをインストールすることを選択できます。
ClusterControlはこれを自動的にセットアップし、PostgreSQLチェック用のxinetdサービスも含みます。これは、以下のようにnetstatで確認できます
[email protected]:~# netstat -tlv4np|grep haproxy
tcp 0 0 0.0.0.0:5433 0.0.0.0:* LISTEN 28441/haproxy
tcp 0 0 0.0.0.0:5434 0.0.0.0:* LISTEN 28441/haproxy
tcp 0 0 0.0.0.0:9600 0.0.0.0:* LISTEN 28441/haproxy
ポート5433は読み取り/書き込みであり、5444は読み取り専用です。
PostgreSQLの場合、以下に示すようにxinetdサービス、つまりpostgreshkを確認します。
[email protected]:~# cat /etc/xinetd.d/postgreschk
# 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
}
xinetdサービスも/etc/ servicesに依存しているため、マップするように指定されているポートを見つけることができる場合があります。
[email protected]:~# grep postgreschk /etc/services
postgreschk 9201/tcp
postgreschkのポートをマップするポートに変更する必要がある場合は、サービス構成ファイルとは別にこのファイルも変更する必要があります。その後、xinetdデーモンを再起動することを忘れないでください。
postgreschkサービスには、書き込み可能かどうか、つまりプライマリまたはマスターであるかどうかを基本的にチェックする外部ファイルへの参照が含まれています。ノードがリカバリ中の場合、それはレプリカまたはリカバリノードです。
[email protected]:~# cat /usr/local/sbin/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='localhost'
export PGUSER='s9smysqlchk'
export PGPASSWORD='password'
export PGPORT='7653'
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";
ユーザーとパスワードの組み合わせは、PostgreSQLサーバーで有効なROLEである必要があります。 ClusterControlを介してインストールしているため、これは自動的に処理されます。
HAProxyが完全にインストールされたので、この設定により、読み取り/書き込みがプライマリノードまたは書き込み可能ノードに送信される読み取り/書き込み分割が可能になりますが、プライマリノードとセカンダリノードの両方で読み取り専用/リカバリノード。この設定は、すでにパフォーマンスが高いことを意味するものではありません。負荷分散のためのHAProxyの組み合わせにより、アプリケーションとそれぞれのデータベースクライアントのパフォーマンスがさらに向上するため、前述のように調整されています。