ハンズオン: PostgreSQLシャーディング(翻訳)

こんにちは、hachi8833です。Craig KerstiensのPostgreSQL記事の翻訳をお送りします。

シャーディング(sharding)はデータを複数サーバーに分散させる機能ですが、導入はそれなりに慎重に行う方がよさそうです。

shard n. (陶器・土器などの)破片.

概要

原著者の許諾を得て翻訳・公開いたします。

ハンズオン: PostgreSQLシャーディング(翻訳)

原注: この記事の内容の多くは現在も有効ですが、今ならCitusの方がもっと直接的に有効です。この記事の公開後、pg_shardは非推奨になっていますが、Citusにはpg_shard機能のオープンソース版の上位セットがあるほか、クラウドも提供しています。シャーディングについてのより詳しいガイドは、Citusのブログドキュメントをご覧ください。


私がデータベースのシャーディングの概要について記事を書いたのは2012年のことでした。以来いくつかの質問を受けていましたが、ここ2か月で質問の数が急増しています。そこで考えた末、ささやかながらシャーディングのハンズオンを行ってシャーディングを深掘りしてみようと思いました。このハンズオンでは、スクラッチでメカニズムをこしらえる代わりにpg_shardを利用することにもっぱら力を注ぎました。

pg_shard(訳注: 現在はCitusが正式です)をご存じない方向けに説明します。これはCitus Dataが提供するオープンソースのPostgreSQL拡張です。Citus Dataといえばpg_shard++などの商用ソフトェアを連想する方も多いと思いますが、もちろん他にも多くの製品があります。pg_shardで機能をわずかに追加することで、データを自動的に分散できるようになります。分散先が他のPostgreSQLテーブルの場合は論理シャーディング、PostgreSQL データベース/インスタンスの場合は物理シャーディングと呼ばれます。これにより、シンプルさを保ちながら単体のPostgreSQLノードを拡大することができます。

前置きはこのぐらいにして、さっそくハンズオンを始めてみましょう。

ビルドとインストール

ここからは、Mac上で動作するPostgreSQL.app(バージョン9.5)を前提としますが、手順の多くは他のPostgreSQLインストールやOS環境にも簡単に応用できます。

PATH=/Applications/Postgres.app/Contents/Versions/latest/bin/:$PATH make

sudo PATH=/Applications/Postgres.app/Contents/Versions/latest/bin/:$PATH make install

cp /Applications/Postgres.app/Contents/Versions/9.5/share/postgresql/postgresql.conf.sample /Applications/Postgres.app/Contents/Versions/9.5/share/postgresql/postgresql.conf.sample

postgresql.confを以下のように修正します。

#shared_preload_libraries = ''
↓
shared_preload_libraries = 'pg_shard'

続いて/Users/craig/Library/Application\ Support/Postgres/var-9.5/pg_worker_list.confに以下のファイルを作成します。パスのcraigは自分のユーザー名に置き換えてください。

# hostname port-number
localhost  5432
localhost  5433

続いてPostgreSQLインスタンスを作成します。

initdb -D /Users/craig/Library/Application\ Support/Postgres/var-9.5-2

新しく作成されたフォルダ内のpostgresql.confの2箇所で以下を変更します。

port = 5432
↓
port = 5433

最後にデータベースを設定して起動します。

createdb instagram
postgres -D /Users/craig/Library/Application\ Support/Postgres/var-9.5-2

設定

これで2つのPostgreSQLインスタンスが動きましたので、pg_shard拡張をオンにし、テーブルをいくつか作って確認しましょう。まず実行中のPostgreSQLインスタンスのうちメインの方に接続します。ここでは最初にInstagramのデータベースを作成していたので、以下のように設定します。

CREATE EXTENSION pg_shard;
CREATE TABLE customer_reviews (customer_id TEXT NOT NULL, review_date DATE, review_rating INTEGER, product_id CHAR(10));

 CREATE TABLE
 Time: 4.734 ms

SELECT master_create_distributed_table(table_name := 'customer_reviews',                                                                                                     partition_column := 'customer_id');

 master_create_distributed_table
 ---------------------------------

 (1 row)

SELECT master_create_worker_shards(table_name := 'customer_reviews',                                                                                                     shard_count := 16,                                                                                                                                        replication_factor := 2);

 master_create_worker_shards
 -----------------------------

 (1 row)

仕組みの理解と利用法

最初の設定は以上です。これだけで、共有アプリケーションが理論上最大16インスタンスまでスケール可能になりました。リフレッシャーを使いたい場合、物理シャーディングと論理シャーディングで異なる部分がひとつあります。この場合、論理シャーディングを16インスタンスに拡大し、同じインスタンスから2つの物理PostgreSQLインスタンス間でレプリケーションできます。

データを操作して見る前に、中の様子を少し見てみましょう。まだ接続を切っていなければ、\dを実行して以下を表示します。

List of relations
Schema | Name | Type | Owner
——–+————————+——-+——-
public | customer_reviews | table | craig
public | customer_reviews_10000 | table | craig
public | customer_reviews_10001 | table | craig
public | customer_reviews_10002 | table | craig
public | customer_reviews_10003 | table | craig
public | customer_reviews_10004 | table | craig
public | customer_reviews_10005 | table | craig
public | customer_reviews_10006 | table | craig
public | customer_reviews_10007 | table | craig
public | customer_reviews_10008 | table | craig
public | customer_reviews_10009 | table | craig
public | customer_reviews_10010 | table | craig
public | customer_reviews_10011 | table | craig
public | customer_reviews_10012 | table | craig
public | customer_reviews_10013 | table | craig
public | customer_reviews_10014 | table | craig
public | customer_reviews_10015 | table | craig
(17 rows)

customer_reviewsテーブルがたくさん並んでいます。参考までに申し上げると、これらのテーブルは昔ながらの単なるPostgreSQLのテーブルであり、これらについては何もする必要もなければ気にする必要もありません。これらにクエリをかけたり変更もできます。この不思議なcustomer_reviewsは実際にはすべての論理シャーディング(テーブル)や物理シャーディング(複数マシンに分散)にデータを分散しています。

production環境でプライマリDBを実際にはワーカーとしては使っていない場合に合わせ、ローカルのMacで設定する方法もご紹介します。具体的には、プライマリとは別に複数のワーカーを使うのが普通なので、pg_worker_list.confでポートを設定します。通常、以下のような構成になります。

続いてINSERTを実行します。

INSERT INTO customer_reviews (customer_id, review_rating) VALUES ('HN802', 5);
INSERT INTO customer_reviews (customer_id, review_rating) VALUES ('FA2K1', 10);

ご興味のある方は、保存されているデータがどのように表現されるかについて各自調べてみてください。

まとめ

pg_shardには多くの制限事項がありますので、pg_shardリポジトリをご覧ください。それでもpg_shardはそのままで非常に有用であり、さまざまなシャーディング設定が可能です。アプリでのシャーディングを検討してはいるものの未導入であれば、pg_shardを使えばわずかな手間でアプリをスケールできるようになります。

次回は、いくつかの言語で有用なシャーディング利用法を見てみることにします。

関連記事(PostgreSQL)

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ