<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Redis &#8211; SRA OSS Tech Blog</title>
	<atom:link href="https://www.sraoss.co.jp/tech-blog/tag/redis/feed/index.xml" rel="self" type="application/rss+xml" />
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<description>OSS専門の技術ブログ。PostgreSQL、Zabbixを中心に10種類以上のOSSの解説、アップデート情報、運用ヒントを提供。</description>
	<lastBuildDate>Fri, 23 Oct 2026 06:40:55 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2018/07/blog-icon-150x150.png</url>
	<title>Redis &#8211; SRA OSS Tech Blog</title>
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>redis_fdw による PostgreSQL と Redis の連携</title>
		<link>https://www.sraoss.co.jp/tech-blog/pgsql/redis_fdw/</link>
		
		<dc:creator><![CDATA[佐藤 友章 (Tomoaki Sato)]]></dc:creator>
		<pubDate>Wed, 03 Aug 2022 05:06:26 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[redis_fdw]]></category>
		<category><![CDATA[サードパーティーソフトウェア]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=10712</guid>

					<description><![CDATA[redis_fdw は、リレーショナルデータベース PostgreSQL からキーバリューストア Redis にアクセスする拡張モジュールです。redis_fdw を使うことで、高速なデータの読み書きができる Redis ...]]></description>
										<content:encoded><![CDATA[<p>redis_fdw は、リレーショナルデータベース PostgreSQL からキーバリューストア Redis にアクセスする拡張モジュールです。redis_fdw を使うことで、高速なデータの読み書きができる Redis と、SQL で複雑なデータの操作ができる PostgreSQL 間で円滑なデータの連携ができます。</p>
<p>この記事では、redis_fdw の概要、インストール、基本的な使い方、テーブルオプションについて説明します。なお、Redis 自体の説明については <a href="https://www.sraoss.co.jp/tech-blog/redis/redis-introduction/">Redis の紹介</a> をお読みください。</p>
<p><span id="more-10712"></span></p>
<h2 id="about">redis_fdw とは</h2>
<p>redis_fdw の名前につく fdw は外部データラッパ (Foreign Data Wrapper) を表し、PostgreSQL から Oracle や CSV ファイルなど、PostgreSQL 外のデータに外部テーブルとしてアクセスする機能です。redis_fdw はこの機能を使って Redis 上のデータにアクセスします。</p>
<p style="text-align: center;"><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/07/redis_fdw-system.png" /></p>
<p><a href="https://github.com/pg-redis-fdw/redis_fdw">redis_fdw</a> は、もともと PostgreSQL 開発者の一人 Dave Page 氏が実験的に開発し、その後、Andrew Dunstan 氏が開発を引き継ぎ、本番利用向けに改修しました。</p>
<p>ソースコードは GitHub リポジトリ上で公開され、PostgreSQL ライセンスに従って配布されています。PostgreSQL の対応バージョンは 9.1 以降で、2022 年 8 月時点で最新の PostgreSQL 14 にも対応しています。</p>
<p>なお、PGDG リポジトリ<sup><a href="#footnote-1">[1]</a></sup> で同じ名前のパッケージが配布されていますが、ここで取り上げる redis_fdw とは異なるもので、便宜上、リポジトリ名をとって rw_redis_fdw と呼びます。</p>
<p><a href="https://github.com/nahanni/rw_redis_fdw">rw_redis_fdw</a> も Redis 用外部データラッパで、名前につく rw は読み書き (Read-Write) を表し、以前は書き込みに対応していなかった redis_fdw に対して名づけられたものと考えられますが、現在は redis_fdw も書き込みに対応しています。</p>
<p>rw_redis_fdw は redis_fdw に比べて機能は多いですが、ここでは、より広く使われている redis_fdw を取り上げます。</p>
<h2 id="install">redis_fdw のインストール</h2>
<p>redis_fdw をインストールします。</p>
<p>ここでは、Rocky Linux 8 上に PostgreSQL、Redis をセットアップした上、redis_fdw をソースコードからビルドし、インストールします。</p>
<ol>
<li>PGDG リポジトリをインストールします。
<pre>$ <b>sudo dnf -qy install https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %rhel-%_arch)/pgdg-redhat-repo-latest.noarch.rpm</b>

Installed:
  pgdg-redhat-repo-42.0-24.noarch

</pre>
<p>PostgreSQL は PGDG リポジトリからインストールします。</p>
<p>これ以降、<code>dnf</code> コマンドの実行時に署名つきパッケージの検証に必要な PGP キーの取り込みを表すメッセージが出力される場合があります。</li>
<li>PostgreSQL モジュールを無効にします。
<pre>$ <b>sudo dnf -qy module disable postgresql</b>
</pre>
<p>OS 標準のリポジトリからも PostgreSQL をインストールできますが、バージョンが古いので、PGDG リポジトリのほうを使うように、PostgreSQL モジュールを無効にしています。</li>
<li>PostgreSQL をインストールします。
<pre>$ <b>sudo dnf -qy install postgresql14-server</b>

Installed:
  lz4-1.8.3-3.el8_4.x86_64
  postgresql14-14.4-1PGDG.rhel8.x86_64
  postgresql14-libs-14.4-1PGDG.rhel8.x86_64
  postgresql14-server-14.4-1PGDG.rhel8.x86_64

</pre>
<p>ここでは、PostgreSQL 14 をインストールしています。</p>
<p>パッケージ名 <code>postgresql14-server</code> をはじめ、これ以降、コマンドラインに含まれる <code>14</code> は PostgreSQL のバージョンを表します。お使いになるバージョンに合わせ、適宜、読み替えてください。</li>
<li>データベースクラスタを作成します。
<pre>$ <b>PGSETUP_INITDB_OPTIONS="-E UTF8 --no-locale" sudo -E /usr/pgsql-14/bin/postgresql-14-setup initdb</b>
Initializing database ... OK

</pre>
<p>データベースクラスタはデータベースを格納する領域です。作成には通常 <code>initdb</code> コマンドを使いますが、ここでは、パッケージに付属のスクリプトを使います。</p>
<p>環境変数 <code>PGSETUP_INITDB_OPTIONS</code> には <code>initdb</code> コマンドに渡すオプションを指定します。ここでは、デフォルトのエンコーディングを UTF8、ロケールをなしに指定しています。</li>
<li>PostgreSQL のサービスを起動します。
<pre>$ <b>sudo systemctl start postgresql-14</b>
</pre>
</li>
<li>Redis をインストールします。
<pre>$ <b>sudo dnf -qy install redis</b>

Installed:
  redis-5.0.3-5.module+el8.5.0+657+2674830e.x86_64

</pre>
</li>
<li>Redis のサービスを起動します。
<pre>$ <b>sudo systemctl start redis</b>
</pre>
</li>
<li>EPEL リポジトリ<sup><a href="#footnote-2">[2]</a></sup> をインストールします。
<pre>$ <b>sudo dnf -qy install epel-release</b>

Installed:
  epel-release-8-13.el8.noarch

</pre>
<p>redis_fdw の動作に必要な Redis 用 C 言語ライブラリ Hiredis は EPEL リポジトリからインストールします。</li>
<li>redis_fdw のビルドに必要なパッケージをインストールします。
<pre>$ <b>sudo dnf -qy install make redhat-rpm-config postgresql14-devel hiredis-devel</b>

Upgraded:
  libgcc-8.5.0-10.1.el8_6.x86_64          libgomp-8.5.0-10.1.el8_6.x86_64
  libstdc++-8.5.0-10.1.el8_6.x86_64
Installed:
  annobin-10.29-3.el8.x86_64
  binutils-2.30-113.el8.x86_64
  clang-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  clang-devel-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  clang-libs-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  clang-resource-filesystem-13.0.1-2.module+el8.6.0+987+d36ea6a1.x86_64
  clang-tools-extra-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  cmake-filesystem-3.20.2-4.el8.x86_64
  compiler-rt-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  cpp-8.5.0-10.1.el8_6.x86_64
  dwz-0.12-10.el8.x86_64
  efi-srpm-macros-3-3.el8.noarch
  emacs-filesystem-1:26.1-7.el8.noarch
  gcc-8.5.0-10.1.el8_6.x86_64
  gcc-c++-8.5.0-10.1.el8_6.x86_64
  ghc-srpm-macros-1.4.2-7.el8.noarch
  glibc-devel-2.28-189.5.el8_6.x86_64
  glibc-headers-2.28-189.5.el8_6.x86_64
  go-srpm-macros-2-17.el8.noarch
  hiredis-0.13.3-13.el8.x86_64
  hiredis-devel-0.13.3-13.el8.x86_64
  isl-0.16.1-6.el8.x86_64
  kernel-headers-4.18.0-372.13.1.el8_6.x86_64
  libicu-devel-60.3-2.el8_1.x86_64
  libmpc-1.1.0-9.1.el8.x86_64
  libomp-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  libomp-devel-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  libstdc++-devel-8.5.0-10.1.el8_6.x86_64
  libxcrypt-devel-4.1.1-6.el8.x86_64
  llvm-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  llvm-devel-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  llvm-libs-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  llvm-static-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  llvm-test-13.0.1-1.module+el8.6.0+825+7e27476a.x86_64
  make-1:4.2.1-11.el8.x86_64
  ocaml-srpm-macros-5-4.el8.noarch
  openblas-srpm-macros-2-2.el8.noarch
  perl-srpm-macros-1-25.el8.noarch
  postgresql14-devel-14.4-1PGDG.rhel8.x86_64
  python-rpm-macros-3-41.el8.noarch
  python-srpm-macros-3-41.el8.noarch
  python3-rpm-macros-3-41.el8.noarch
  qt5-srpm-macros-5.15.2-1.el8.0.1.noarch
  redhat-rpm-config-129-1.el8.noarch
  rust-srpm-macros-5-2.el8.noarch
  unzip-6.0-46.el8.x86_64
  zip-3.0-23.el8.x86_64

</pre>
</li>
<li>redis_fdw のソースコードをダウンロードします。
<pre>$ <b>curl -LOs https://github.com/pg-redis-fdw/redis_fdw/archive/refs/heads/REL_14_STABLE.tar.gz</b>
</pre>
<p>redis_fdw のソースコードは PostgreSQL のバージョンごとにブランチが分かれていて、ダウンロード時はブランチ名を指定する必要があります。ここでは、PostgreSQL 14 に対応したブランチ <code>REL_14_STABLE</code> を指定しています。</li>
<li>redis_fdw のソースコードを展開します。
<pre>$ <b>tar -xzf REL_14_STABLE.tar.gz</b>
</pre>
</li>
<li>redis_fdw をビルドします。
<pre>$ <b>make -C redis_fdw-REL_14_STABLE USE_PGXS=1 PG_CONFIG=/usr/pgsql-14/bin/pg_config</b>
make: ディレクトリ '/home/vagrant/redis_fdw-REL_14_STABLE'　に入ります
gcc -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wimplicit-fallthrough=3 -Wcast-function-type -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -Wno-format-truncation -Wno-stringop-truncation -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fPIC -I. -I./ -I/usr/pgsql-14/include/server -I/usr/pgsql-14/include/internal  -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include  -c -o redis_fdw.o redis_fdw.c
gcc -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wimplicit-fallthrough=3 -Wcast-function-type -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -Wno-format-truncation -Wno-stringop-truncation -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fPIC -shared -o redis_fdw.so redis_fdw.o -L/usr/pgsql-14/lib  -Wl,--as-needed -L/usr/lib64  -L/usr/lib64 -Wl,--as-needed -Wl,-rpath,'/usr/pgsql-14/lib',--enable-new-dtags  -lhiredis
/usr/bin/clang -Wno-ignored-attributes -fno-strict-aliasing -fwrapv -Wno-unused-command-line-argument -Wno-compound-token-split-by-macro -O2  -I. -I./ -I/usr/pgsql-14/include/server -I/usr/pgsql-14/include/internal  -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -flto=thin -emit-llvm -c -o redis_fdw.bc redis_fdw.c
make: ディレクトリ '/home/vagrant/redis_fdw-REL_14_STABLE' から出ます
</pre>
<p>引数の変数 <code>USE_PGXS</code> には PostgreSQL 用拡張モジュールの構築基盤 PGXS を使うことを表す <code>1</code>、<code>PG_CONFIG</code> には <code>pg_config</code> コマンドのパスを指定します。</li>
<li>redis_fdw をインストールします。
<pre>$ <b>sudo make -C redis_fdw-REL_14_STABLE install USE_PGXS=1 PG_CONFIG=/usr/pgsql-14/bin/pg_config</b>
make: ディレクトリ '/home/vagrant/redis_fdw-REL_14_STABLE'　に入ります
/usr/bin/mkdir -p '/usr/pgsql-14/lib'
/usr/bin/mkdir -p '/usr/pgsql-14/share/extension'
/usr/bin/mkdir -p '/usr/pgsql-14/share/extension'
/usr/bin/install -c -m 755  redis_fdw.so '/usr/pgsql-14/lib/redis_fdw.so'
/usr/bin/install -c -m 644 .//redis_fdw.control '/usr/pgsql-14/share/extension/'
/usr/bin/install -c -m 644 .//redis_fdw--1.0.sql  '/usr/pgsql-14/share/extension/'
/usr/bin/mkdir -p '/usr/pgsql-14/lib/bitcode/redis_fdw'
/usr/bin/mkdir -p '/usr/pgsql-14/lib/bitcode'/redis_fdw/
/usr/bin/install -c -m 644 redis_fdw.bc '/usr/pgsql-14/lib/bitcode'/redis_fdw/./
cd '/usr/pgsql-14/lib/bitcode' &amp;&amp; /usr/bin/llvm-lto -thinlto -thinlto-action=thinlink -o redis_fdw.index.bc redis_fdw/redis_fdw.bc
make: ディレクトリ '/home/vagrant/redis_fdw-REL_14_STABLE' から出ます
</pre>
<p>ソースコードと、それを展開したディレクトリはインストール後、削除しても構いません。</li>
</ol>
<h2 id="basic-usage">redis_fdw の基本的な使い方</h2>
<p>redis_fdw を使って PostgreSQL から Redis 上のデータを操作してみます。</p>
<ol>
<li>PostgreSQL のスーパーユーザに切り替わります。
<pre>$ <b>sudo su - postgres</b>
</pre>
</li>
<li>データベースを作成します。
<pre>$ <b>createdb redis_db</b>
</pre>
<p>ここでは、<code>redis_db</code> という名前のデータベースを作成しています。</li>
<li>データベースに接続します。
<pre>$ <b>psql redis_db</b>
psql (14.4)
"help"でヘルプを表示します。

=# 
</pre>
<p>ここでは、作成した <code>redis_db</code> データベースに接続しています。終了するには <code>\q</code> または <code>Ctrl</code> + <code>D</code> を入力します。</li>
<li>データベースに redis_fdw をインストールします。
<pre>=# <b>CREATE EXTENSION redis_fdw;</b>
CREATE EXTENSION
</pre>
<p>redis_fdw はプログラムとしてはインストール済みですが、実際に使うにはデータベースごとにインストールする必要があります。</p>
<p>ここでは、接続中の <code>redis_db</code> データベースにインストールしています。</li>
<li>外部サーバを作成します。
<pre>=# <b>CREATE SERVER redis_server
     FOREIGN DATA WRAPPER redis_fdw
     OPTIONS (address '127.0.0.1', port '6379');</b>
CREATE SERVER
</pre>
<p>外部サーバとは、外部データラッパを使って外部データにアクセスするのに必要な接続情報を定義したオブジェクトです。作成時には、外部サーバ名、外部データラッパ名、オプションを指定します。</p>
<p>redis_fdw では、以下のオプションが指定できます。</p>
<table>
<thead>
<tr>
<th>オプション</th>
<th>デフォルト値</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>address</code></td>
<td><code>127.0.0.1</code></td>
<td>Redis サーバの IP アドレスまたはホスト名</td>
</tr>
<tr>
<td><code>port</code></td>
<td><code>6379</code></td>
<td>Redis サーバのポート番号</td>
</tr>
</tbody>
</table>
<p>ここでは、<code>redis_server</code> という名前で redis_fdw の外部サーバを作成しています。オプションは例示のため、指定していますが、デフォルトでよければ、指定する必要はありません。</li>
<li>外部サーバのユーザマッピングを作成します。
<pre>=# <b>CREATE USER MAPPING FOR PUBLIC
     SERVER redis_server
     OPTIONS (password 'secret');</b>
CREATE USER MAPPING
</pre>
<p>外部サーバのユーザマッピングとは、外部サーバとユーザの対応づけを定義したオブジェクトです。作成時には、ユーザ名、外部サーバ名、オプションを指定します。</p>
<p>redis_fdw では、以下のオプションが指定できます。</p>
<table>
<thead>
<tr>
<th>オプション</th>
<th>デフォルト値</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>password</code></td>
<td>(なし)</td>
<td>Redis サーバ接続時の認証に使うパスワード</td>
</tr>
</tbody>
</table>
<p>ここでは、すべてのユーザを表す <code>PUBLIC</code> と外部サーバ <code>redis_server</code> を対応づけるユーザマッピングを作成しています。<code>password</code> オプションはパスワードが未設定であれば、指定する必要はありません。</li>
<li>外部テーブルを作成します。
<pre>=# <b>CREATE FOREIGN TABLE string_table (key text, val text)
     SERVER redis_server
     OPTIONS (database '0');</b>
CREATE FOREIGN TABLE
</pre>
<p>外部テーブルとは、外部データラッパを使って外部データにテーブルとしてアクセスできるように定義した特別なテーブルです。作成時には、テーブル定義、外部サーバ名、オプションを指定します。</p>
<p>redis_fdw では、以下のオプションが指定できます。</p>
<table>
<thead>
<tr>
<th>オプション</th>
<th>デフォルト値</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>database</code></td>
<td><code>0</code></td>
<td>Redis のデータベース番号。<code>0</code> からデフォルトでは <code>15</code> まで指定可能</td>
</tr>
<tr>
<td><code>tabletype</code></td>
<td>(なし)</td>
<td>Redis のデータ型。<code>list</code>、<code>hash</code>、<code>set</code>、<code>zset</code> が指定可能。未指定は <code>string</code></td>
</tr>
<tr>
<td><code>tablekeyprefix</code></td>
<td>(なし)</td>
<td>指定した接頭辞をもつキーに対象データを絞り込む</td>
</tr>
<tr>
<td><code>tablekeyset</code></td>
<td>(なし)</td>
<td>指定したキーをもつ集合に含まれるキーに対象データを絞り込む</td>
</tr>
<tr>
<td><code>singleton_key</code></td>
<td>(なし)</td>
<td>指定したキーの単一データを展開して対象データにする</td>
</tr>
</tbody>
</table>
<p><code>tabletype</code> オプションを指定しないと、文字列を表す <code>string</code> 型になりますが、値として <code>string</code> は指定できません。<code>teblekeyprefix</code>、<code>tablekeyset</code>、<code>singleton_key</code> はいずれも対象データを指定するオプションで、1 つのみ指定でき、指定しないと、すべてのデータが対象になります。詳しくは <a href="#table-options">redis_fdw のテーブルオプション</a> で説明します。</p>
<p style="text-align: center;"><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/07/redis_fdw-string.png" /></p>
<p>ここでは、<code>tabletype</code> オプションは指定せず、テーブル定義は <code>text</code> 型の <code>key</code> と <code>val</code> 列を定義しています。Redis のキーと <code>string</code> 型の値は PostgreSQL ではそれぞれ <code>text</code> 型に対応します。列名は任意です。<code>database</code> オプションはデフォルトでよければ、指定する必要はありません。</li>
<li>外部テーブルのデータを操作します。データの操作を受けて Redis サーバがどう動作するかを確認するため、Redis サーバで実行されたコマンドを出力するようにしておきます。終了するには <code>Ctrl</code> + <code>C</code> を入力します。
<pre>$ <b>redis-cli monitor</b>
OK
</pre>
<p>PostgreSQL 側でデータを 3 件登録します。</p>
<pre>=# <b>INSERT INTO string_table
     VALUES ('key1', 'val1'), ('key2', 'val2'), ('key3', 'val3');</b>
INSERT 0 3
</pre>
<p>Redis 側で実行されたコマンドが出力されます。</p>
<pre>1658092725.885750 [0 127.0.0.1:46042] "AUTH" "secret"
1658092725.886005 [0 127.0.0.1:46042] "SELECT" "0"
1658092725.886333 [0 127.0.0.1:46042] "EXISTS" "key1"
1658092725.886766 [0 127.0.0.1:46042] "SET" "key1" "val1"
1658092725.887016 [0 127.0.0.1:46042] "EXISTS" "key2"
1658092725.887387 [0 127.0.0.1:46042] "SET" "key2" "val2"
1658092725.887620 [0 127.0.0.1:46042] "EXISTS" "key3"
1658092725.887764 [0 127.0.0.1:46042] "SET" "key3" "val3"
</pre>
<p>PostgreSQL 側でデータを 1 件更新します。</p>
<pre>=# <b>UPDATE string_table SET val = 'val4' WHERE key = 'key1';</b>
UPDATE 1
</pre>
<p>Redis 側で実行されたコマンドが出力されます。</p>
<pre>1658092937.940434 [0 127.0.0.1:46044] "AUTH" "secret"
1658092937.940542 [0 127.0.0.1:46044] "SELECT" "0"
1658092937.940660 [0 127.0.0.1:46044] "DBSIZE"
1658092937.941136 [0 127.0.0.1:46046] "AUTH" "secret"
1658092937.941352 [0 127.0.0.1:46046] "SELECT" "0"
1658092937.941445 [0 127.0.0.1:46046] "EXISTS" "key1"
1658092937.941835 [0 127.0.0.1:46048] "AUTH" "secret"
1658092937.941976 [0 127.0.0.1:46048] "SELECT" "0"
1658092937.942118 [0 127.0.0.1:46046] "GET" "key1"
1658092937.942385 [0 127.0.0.1:46048] "SET" "key1" "val4"
</pre>
<p>PostgreSQL 側でデータを 1 件削除します。</p>
<pre>=# <b>DELETE FROM string_table WHERE key = 'key2';</b>
DELETE 1
</pre>
<p>Redis 側で実行されたコマンドが出力されます。</p>
<pre>1658092947.811658 [0 127.0.0.1:46050] "AUTH" "secret"
1658092947.811792 [0 127.0.0.1:46050] "SELECT" "0"
1658092947.811875 [0 127.0.0.1:46050] "DBSIZE"
1658092947.812375 [0 127.0.0.1:46052] "AUTH" "secret"
1658092947.812605 [0 127.0.0.1:46052] "SELECT" "0"
1658092947.812729 [0 127.0.0.1:46052] "EXISTS" "key2"
1658092947.813055 [0 127.0.0.1:46054] "AUTH" "secret"
1658092947.813197 [0 127.0.0.1:46054] "SELECT" "0"
1658092947.813342 [0 127.0.0.1:46052] "GET" "key2"
1658092947.813438 [0 127.0.0.1:46054] "DEL" "key2"
</pre>
<p>PostgreSQL 側でデータを 1 件取得します。</p>
<pre>=# <b>SELECT val FROM string_table WHERE key = 'key3';</b>
 val
------
 val3
(1 行)

</pre>
<p>Redis 側で実行されたコマンドが出力されます。</p>
<pre>1658092954.987736 [0 127.0.0.1:46056] "AUTH" "secret"
1658092954.987827 [0 127.0.0.1:46056] "SELECT" "0"
1658092954.987876 [0 127.0.0.1:46056] "DBSIZE"
1658092954.988113 [0 127.0.0.1:46058] "AUTH" "secret"
1658092954.988283 [0 127.0.0.1:46058] "SELECT" "0"
1658092954.988375 [0 127.0.0.1:46058] "EXISTS" "key3"
1658092954.988482 [0 127.0.0.1:46058] "GET" "key3"
</pre>
</li>
</ol>
<h2 id="table-options">redis_fdw のテーブルオプション</h2>
<p>redis_fdw を使って外部テーブルの定義時に指定できるオプションについて説明します。</p>
<h3 id="tabletype-option"><code>tabletype</code> オプション</h3>
<p><code>tabletype</code> は Redis のデータ型を指定するオプションです。オプションに指定できるデータ型について説明します。</p>
<h4 id="list-type"><code>list</code> 型</h4>
<p><code>list</code> は登録順に並べた文字列の集合を表すデータ型で、PostgreSQL では値を並べた <code>text</code> 型の配列に対応します。</p>
<pre>=# <b>CREATE FOREIGN TABLE list_table (key text, val text[])
     SERVER redis_server
     OPTIONS (database '1', tabletype 'list');</b>
CREATE FOREIGN TABLE
=# <b>INSERT INTO list_table
     VALUES ('key1', '{val1,val2,val3,val1}');</b>
INSERT 0 1
=# <b>SELECT * FROM list_table WHERE key = 'key1';</b>
 key  |          val
------+-----------------------
 key1 | {val1,val2,val3,val1}
(1 行)

=# <b>SELECT key, unnest(val) FROM list_table WHERE key = 'key1';</b>
 key  | unnest
------+--------
 key1 | val1
 key1 | val2
 key1 | val3
 key1 | val1
(4 行)

</pre>
<p>値 <code>val1</code>、<code>val2</code>、<code>val3</code>、<code>val1</code> を登録し、データを取得すると、値が登録順に並び、重複する値 <code>val1</code> が残っています。取得したデータは <code>unnest</code> 関数で行の集合に展開できます。</p>
<h4 id="hash-type"><code>hash</code> 型</h4>
<p><code>hash</code> はフィールドと値の文字列の組み合わせからなる集合を表すデータ型で、PostgreSQL ではフィールドと値を交互に並べた <code>text</code> 型の配列に対応します。</p>
<pre>=# <b>CREATE FOREIGN TABLE hash_table (key text, val text[])
     SERVER redis_server
     OPTIONS (database '2', tabletype 'hash');</b>
CREATE FOREIGN TABLE
=# <b>INSERT INTO hash_table
     VALUES ('key1', '{fld1,val1,fld2,val2,fld3,val3,fld1,val4}');</b>
INSERT 0 1
=# <b>SELECT * FROM hash_table WHERE key = 'key1';</b>
 key  |               val
------+---------------------------------
 key1 | {fld1,val4,fld2,val2,fld3,val3}
(1 行)

=# <b>SELECT key, json_object(val) FROM hash_table WHERE key = 'key1';</b>
 key  |                     json_object
------+-----------------------------------------------------
 key1 | {"fld1" : "val4", "fld2" : "val2", "fld3" : "val3"}
(1 行)

=# <b>SELECT key, (json_each_text(json_object(val))).*
     FROM hash_table WHERE key = 'key1';</b>
 key  | key  | value
------+------+-------
 key1 | fld1 | val4
 key1 | fld2 | val2
 key1 | fld3 | val3
(3 行)

</pre>
<p>フィールドと値の組み合わせ <code>fld1</code> と <code>val1</code>、<code>fld2</code> と <code>val2</code>、<code>fld3</code> と <code>val3</code>、<code>fld1</code> と <code>val4</code> を登録し、データを取得すると、フィールド <code>fld1</code> が重複する値 <code>val1</code>、<code>val4</code> はあとから登録した値 <code>val4</code> で上書きされています。取得したデータは <code>json_object</code> 関数で JSON オブジェクトに変換し、さらに <code>json_each_text</code> 関数でフィールドと値からなる行の集合に展開できます。</p>
<h4 id="set-type"><code>set</code> 型</h4>
<p><code>set</code> は順序づけがなく、重複がない文字列の集合を表すデータ型で、PostgreSQL では値を並べた <code>text</code> 型の配列に対応します。</p>
<pre>=# <b>CREATE FOREIGN TABLE set_table (key text, val text[])
     SERVER redis_server
     OPTIONS (database '3', tabletype 'set');</b>
CREATE FOREIGN TABLE
=# <b>INSERT INTO set_table
     VALUES ('key1', '{val1,val2,val3,val1}');</b>
INSERT 0 1
=# <b>SELECT * FROM set_table WHERE key = 'key1';</b>
 key  |       val
------+------------------
 key1 | {val1,val3,val2}
(1 行)

</pre>
<p>値 <code>val1</code>、<code>val2</code>、<code>val3</code>、<code>val1</code> を登録し、データを取得すると、重複する値 <code>val1</code> が取り除かれ、1 つになっています。</p>
<h4 id="zset-type"><code>zset</code> 型</h4>
<p><code>zset</code> はスコアで順序づけした、重複がない文字列の集合を表すデータ型で、PostgreSQL では値を並べた <code>text</code> 型の配列に対応します。</p>
<p><code>zset</code> 型の使い方は基本的に <code>set</code> 型と同じです。スコアは登録順に <code>0</code>、<code>1</code>、<code>2</code>、&#8230; が割り当てられます。スコアを PostgreSQL で扱うには、<a href="#singleton_key-option"><code>singleton_key</code> オプション</a> を指定する必要があります。</p>
<h3 id="tablekeyprefix-option"><code>tablekeyprefix</code> オプション</h3>
<p><code>tablekeyprefix</code> は指定した接頭辞をもつキーに対象データを絞り込むオプションで、1 つのデータベース内に異なる種類のデータをもたせ、別テーブルとしてアクセスするのに役立ちます。</p>
<p style="text-align: center;"><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/07/redis_fdw-keyprefix.png" /></p>
<pre>=# <b>CREATE FOREIGN TABLE keyprefix_table (key text, val text)
     SERVER redis_server
     OPTIONS (database '4', tablekeyprefix 'keyprefix_table:');</b>
CREATE FOREIGN TABLE
=# <b>INSERT INTO keyprefix_table VALUES ('keyprefix_table:key1', 'val1');</b>
INSERT 0 1
=# <b>INSERT INTO keyprefix_table VALUES ('keyprefix_table:key2', 'val2');</b>
INSERT 0 1
=# <b>INSERT INTO keyprefix_table VALUES ('key3', 'val3');</b>
ERROR:  key 'key3' does not match table key prefix 'keyprefix_table:'
=# <b>SELECT * FROM keyprefix_table;</b>
     key          | val
----------------------+------
 keyprefix_table:key2 | val2
 keyprefix_table:key1 | val1
(2 行)

=# <b>\! redis-cli -n 4 SET key3 val3</b>
OK
=# <b>\! redis-cli -n 4 KEYS \*</b>
1) "keyprefix_table:key2"
2) "key3"
3) "keyprefix_table:key1"
=# <b>SELECT * FROM keyprefix_table;</b>
     key          | val
----------------------+------
 keyprefix_table:key2 | val2
 keyprefix_table:key1 | val1
(2 行)

</pre>
<p><code>tablekeyprefix</code> オプションを指定すると、指定した接頭辞 <code>keyprefix_table:</code> をもつキー <code>keyprefix_table:key1</code>、<code>keyprefix_table:key2</code> のデータしか登録できず、接頭辞をもたないキー <code>key3</code> の登録はエラーになります。<code>\!</code> は PostgreSQL 外のコマンドを実行するコマンドで、Redis 上のデータを直接操作し、接頭辞をもたないキー <code>key3</code> を登録し、データを取得すると、接頭辞をもたないキー <code>key3</code> は結果に現れません。</p>
<p>大量のキーをもつデータベースでは、<code>tablekeyprefix</code> オプションではキーの検索に時間がかかるため、<code>tablekeyset</code> オプションでキーを集合に含まれるものに限ったほうがよいでしょう。</p>
<h3 id="tablekeyset-option"><code>tablekeyset</code> オプション</h3>
<p><code>tablekeyset</code> は指定したキーをもつ集合に含まれるキーに対象データを絞り込むオプションで、<code>tablekeyprefix</code> オプションと同じく、1 つのデータベース内で異なる種類のデータを扱うのに使います。</p>
<p style="text-align: center;"><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/07/redis_fdw-keyset.png" /></p>
<pre>=# <b>CREATE FOREIGN TABLE keyset_table (key text, val text)
     SERVER redis_server
     OPTIONS (database '5', tablekeyset 'keyset_table_keys');</b>
CREATE FOREIGN TABLE
=# <b>INSERT INTO keyset_table
     VALUES ('key1', 'val1'), ('key2', 'val2'), ('key3', 'val3');</b>
INSERT 0 3
=# <b>SELECT * FROM keyset_table;</b>
 key  | val
------+------
 key3 | val3
 key2 | val2
 key1 | val1
(3 行)

=# <b>\! redis-cli -n 5 SREM keyset_table_keys key2</b>
(integer) 1
=# <b>\! redis-cli -n 5 SMEMBERS keyset_table_keys</b>
1) "key3"
2) "key1"
=# <b>SELECT * FROM keyset_table;</b>
 key  | val
------+------
 key3 | val3
 key1 | val1
(2 行)

</pre>
<p><code>tablekeyset</code> オプションを指定すると、指定したキー <code>keyset_table_keys</code> をもつ集合に登録したキー <code>key1</code>、<code>key2</code>、<code>key3</code> が自動的に登録され、取得されるデータは集合に含まれるキーに限られます。Redis 上のデータを直接操作し、キー <code>key2</code> を削除し、データを取得すると、削除したキー <code>key2</code> は結果に現れなくなります。</p>
<h3 id="singleton_key-option"><code>singleton_key</code> オプション</h3>
<p><code>singleton_key</code> は指定したキーの単一データを展開して対象データにするオプションで、<code>tableytpe</code> オプション指定なしの <code>string</code> 型は 1 行 1 列、指定ありの <code>list</code> または <code>set</code> 型は行の集合、<code>hash</code> 型はフィールドと値からなる行の集合、<code>zset</code> 型は値とスコアからなる行の集合に展開されます。</p>
<p style="text-align: center;"><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/07/redis_fdw-singleton.png" /></p>
<pre>=# <b>CREATE FOREIGN TABLE singleton_table (val text, sc numeric)
     SERVER redis_server
     OPTIONS (database '6', tabletype 'zset', singleton_key 'singleton_table');</b>
CREATE FOREIGN TABLE
=# <b>INSERT INTO singleton_table
     VALUES ('val1', 10), ('val2', 20), ('val3', 30);</b>
INSERT 0 3
=# <b>SELECT * FROM singleton_table;</b>
 val  | sc
------+----
 val1 | 10
 val2 | 20
 val3 | 30
(3 行)

=# <b>UPDATE singleton_table SET sc = 40 WHERE val = 'val1';</b>
UPDATE 1
=# <b>SELECT * FROM singleton_table;</b>
 val  | sc
------+----
 val2 | 20
 val3 | 30
 val1 | 40
(3 行)

</pre>
<p><code>singleton_key</code> オプションと併せて <code>tabletype</code> オプションに <code>zset</code> 型を指定すると、PostgreSQL でスコアを扱えるようになります。スコアは PostgreSQL では <code>numeric</code> 型に対応します。<code>ORDER BY</code> 句で並び順を指定しなければ、データはスコアの昇順に取得されます。値 <code>val1</code> のスコアを <code>10</code> から <code>40</code> に更新すると、並び順が更新したスコア順に変わり、値 <code>val1</code> は最後に来るようになります。</p>
<h2 id="conclusion">おわりに</h2>
<p>この記事では、Redis 用外部データラッパ redis_fdw の概要、インストール、基本的な使い方、テーブルオプションについて説明しました。redis_fdw を使うことで、高速なデータの読み書きができる Redis と、SQL で複雑なデータの操作ができる PostgreSQL の特長を互いに活かし、さらに利用の幅が広がることでしょう。</p>
<p>SRA OSS では、PostgreSQL や Redis、redis_fdw のサポートをはじめとして、オープンソースに関する様々なサービスを提供しています。SRA OSS のサービスに興味がありましたら、お気軽に <a href="https://www.sraoss.co.jp/contact.php">こちら</a> からお問い合わせください。</p>
<hr />
<ol>
<li id="footnote-1">PostgreSQL Global Development Group (PGDG) が運営する PostgreSQL 関連パッケージの Yum リポジトリ</li>
<li id="footnote-2">Fedora Project が運営するエンタープライズ Linux 向け追加パッケージ (Extra Packages for Enterprise Linux; EPEL) の Yum リポジトリ</li>
</ol>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/pgsql-mainte/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-pgsql" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、PostgreSQL/Pgpool-II のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Redisモジュールの解説</title>
		<link>https://www.sraoss.co.jp/tech-blog/redis/redis-modules/</link>
		
		<dc:creator><![CDATA[山本 博之 (Hiroyuki Yamamoto)]]></dc:creator>
		<pubDate>Thu, 26 Dec 2019 02:00:16 +0000</pubDate>
				<category><![CDATA[Redis]]></category>
		<category><![CDATA[KVS]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=5017</guid>

					<description><![CDATA[Redis 4.0で追加されたモジュール機能により、ユーザがRedisの機能を自由に拡張することができます。 今回はRedisのモジュール機能で可能なことの解説、およびRedisのスポンサーであるRedis Labsや他 ...]]></description>
										<content:encoded><![CDATA[<p>Redis 4.0で追加された<a href="https://redis.io/topics/modules-intro">モジュール機能</a>により、ユーザがRedisの機能を自由に拡張することができます。</p>
<p>今回はRedisのモジュール機能で可能なことの解説、およびRedisのスポンサーであるRedis Labsや他のサードパーティにより公開されている様々なモジュールの紹介を行います。</p>
<p><span id="more-5017"></span></p>
<h2>Redisモジュールとは</h2>
<p>Redisモジュールは、Redisに外部モジュールをロードすることで、Redis本体に手を入れることなく機能拡張できる仕組みです。モジュールは通常C/C++で実装されますが、技術的には他の言語でも実装可能です。</p>
<h2>Redisモジュールで可能なこと</h2>
<p>RedisモジュールではRedisに以下のような機能の拡張が可能です。新しいコマンドを呼び出したときに実行する処理をすべてモジュール側で実装することもできますし、Redisの機能を利用して実装することも可能です。</p>
<ul>
<li>新しいコマンドの作成</li>
<li>Redisの機能をモジュールから呼び出す</li>
<li>新しいデータ型の作成</li>
<li>レプリケーション、クラスタにも対応できる (RDB、AOFの永続化処理を実装すればOK)</li>
</ul>
<h2>Redisモジュールのライセンス変更について</h2>
<p>Redisのスポンサー企業であるRedis Labsが開発、提供するモジュールについてライセンスの変更が行われました。</p>
<p>対象は RediSearch, RedisGraph, RedisJSON, RedisML, RedisBloom などで、当初のAGPLから、(2018/8) Apache v2.0 modified with Commons Clause -&gt; (2019/2) Redis Source Available License (RSAL)と2回の変更が行われました。これは大手クラウド業者などがRedisモジュールの機能をそのままサービスとして提供することで利益を得る、いわゆるフリーライドを防ぐ意図があります。</p>
<p>なお、Redis本体のライセンスには変更はありません(引き続き3条項BSDライセンスが適用されます)。他のRSALを適用していないモジュールや、ユーザーが実装するモジュールにも制限はありません。</p>
<h3>RSALの制限事項</h3>
<p>RSALライセンスではソースコードの利用・改変・再配布や、Redisモジュールを使ったサービスや製品の販売は認められています。ただし、以下の開発に使用することは禁止されています。</p>
<ul>
<li>データベース</li>
<li>キャッシュエンジン</li>
<li>ストリーム処理エンジン</li>
<li>検索エンジン</li>
<li>インデックスエンジン</li>
<li>機械学習(ディープラーニング含む)、AIエンジン</li>
<li>RedisのAPIやRedis Modules APIを公開する製品やサービス</li>
</ul>
<h2>Redisモジュールの作り方</h2>
<p>Redisモジュールをビルドするのに必要なものは、Redisの最新版ソースコードに含まれる redismodule.h のみと非常にシンプルです。ライブラリ等依存コンポーネントがないため、手軽に作成することができます。</p>
<p>Redisのソースコードは以下のページからダウンロードできます。通常はStableを使用してください。</p>
<p><a href="https://redis.io/download">https://redis.io/download</a></p>
<h3>サンプルコード</h3>
<p>helloworld.randコマンドを実行するとrand()で生成した乱数を返す単純なモジュールです。</p>
<pre>#include "redismodule.h"
#include &lt;stdlib.h&gt;

int HelloworldRand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    RedisModule_ReplyWithLongLong(ctx, rand());
    return REDISMODULE_OK;
}

int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (RedisModule_Init(ctx, "helloworld", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR)
        return REDISMODULE_ERR;

    if (RedisModule_CreateCommand(ctx, "helloworld.rand", HelloworldRand_RedisCommand, "readonly", 0, 0, 0) == REDISMODULE_ERR)
        return REDISMODULE_ERR;

    return REDISMODULE_OK;
}</pre>
<h3>コンパイル、配置、ロード</h3>
<pre>$ gcc --shared -fPIC helloworld.c -o helloworld.so
$ sudo cp helloworld.so /var/lib/redis/helloworld.so
$ redis-cli module load /var/lib/redis/helloworld.so
(設定ファイルに書く場合は /etc/redis.conf に以下を追加)
loadmodule /var/lib/redis/helloworld.so</pre>
<h3>実行</h3>
<pre>$ redis-cli
127.0.0.1:6379&gt; helloworld.rand
(integer) 855445334
127.0.0.1:6379&gt; helloworld.rand
(integer) 705120217</pre>
<h2>公開中のモジュールの紹介</h2>
<p>ここではRedisモジュールの活用例として、<a href="https://redis.io/modules">Redis Modules</a>のページで公開されているモジュールの中から興味深いものについていくつか紹介します。</p>
<ul>
<li><strong>RediSearch:</strong> 全文検索</li>
<li><strong>RedisAI/RedisML/neural-redis:</strong> 機械学習エンジン</li>
<li><strong>RedisGraph:</strong> グラフDB</li>
</ul>
<h3>RediSearch</h3>
<p><a href="https://github.com/RediSearch/RediSearch.git">RediSearch</a>はRedisに全文検索エンジンを追加するモジュールです。多言語に対応しており、中国語には対応していますが日本語には残念ながら未対応です(工夫により対応することは可能です)。RediSearchはRedis Labs社によりRSALライセンスで配布されています。</p>
<p>RediSearchのビルド手順は以下のようになります(RHEL7系の場合)。</p>
<pre>$ sudo yum install cmake3 --enablerepo=epel
$ git clone https://github.com/RediSearch/RediSearch.git
$ cd RediSearch; mkdir build; cd build
$ cmake3 .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
$ make
$ sudo cp redisearch.so /var/lib/redis/
$ redis-cli module load "/var/lib/redis/redisearch.so"</pre>
<p>簡単な使い方を以下に示します。</p>
<pre>[スキーマを作成]
127.0.0.1:6379&gt; ft.create myidx schema title text weight 5.0 body text url text

[ドキュメントを追加]
127.0.0.1:6379&gt; ft.add myidx doc1 1.0 fields title "Hello World" body "This is a test document." url "http://localhost/"

[検索]
127.0.0.1:6379&gt; ft.search myidx "test" limit 0 10
1) (integer) 1
2) "doc1"
3) 1) title
2) "Hello World"
3) body
4) "This is a test document."
5) url
6) "http://localhost/"</pre>
<p>あらかじめ分かち書きを行っておくことで日本語も一応使うことが出来ます。</p>
<pre>$ redis-cli --raw ※日本語UTF-8文字列をエスケープせずそのまま出力するため--rawを付加
127.0.0.1:6379&gt; ft.create jpidx schema title text weight 5.0 body text title.orig text weight 0.0 body.orig text weight 0.0
127.0.0.1:6379&gt; ft.add jpidx d2 1.0 fields title "日本語 の テスト" body "これは 試験 用 の 文章 です 。" title.orig "日本語のテスト" body.orig "これは試験用の文章です。"
127.0.0.1:6379&gt; ft.search jpidx 日本語
1
d2
title
日本語 の テスト
body
これは 試験 用 の 文章 です 。
body.orig
これは試験用の文章です。
title.orig
日本語のテスト</pre>
<h3>neural-redis</h3>
<p><a href="https://github.com/antirez/neural-redis">neural-redis</a>はRedisにニューラルネットワークによる機械学習エンジンを追加するモジュールです。以下のような特徴があります。</p>
<ul>
<li>非常にシンプルなAPI</li>
<li>他のライブラリに依存せず単体で動作</li>
<li>データ自動正規化</li>
<li>別スレッドによるバックグラウンド処理</li>
<li>過学習検知付き自動トレーニング</li>
<li>Salvatore Sanfilippo (Redis開発者)が開発</li>
<li>3条項BSDライセンス</li>
</ul>
<p>他の機械学習・ディープラーニングエンジンとして、Redis Labs社により公開されている<a href="https://github.com/RedisLabsModules/redisml">RedisML</a>および<a href="https://github.com/RedisAI/RedisAI">RedisAI</a>があります。</p>
<p>neural-redisのビルド手順は以下のようになります。</p>
<pre>$ git clone https://github.com/antirez/neural-redis
$ cd neural-redis/
$ make sse
$ sudo cp neuralredis.so /var/lib/redis/
$ redis-cli module load "/var/lib/redis/neuralredis.so"</pre>
<h4>neural-redis (1) 回帰分析</h4>
<p>入力データから数値の予測を行う問題の例として、足し算の答えの予測 (a + b = c)を行います。</p>
<h5>ニューラルネットワークの作成</h5>
<pre>$ redis-cli
127.0.0.1:6379&gt; NR.CREATE net REGRESSOR 2 3 -&gt; 1 NORMALIZE DATASET 50 TEST 10
(integer) 13</pre>
<h5>学習データを投入</h5>
<pre>127.0.0.1:6379&gt; NR.OBSERVE net 1 2 -&gt; 3
127.0.0.1:6379&gt; NR.OBSERVE net 4 5 -&gt; 9
127.0.0.1:6379&gt; NR.OBSERVE net 3 4 -&gt; 7
127.0.0.1:6379&gt; NR.OBSERVE net 1 1 -&gt; 2
127.0.0.1:6379&gt; NR.OBSERVE net 2 2 -&gt; 4
127.0.0.1:6379&gt; NR.OBSERVE net 0 9 -&gt; 9
127.0.0.1:6379&gt; NR.OBSERVE net 7 5 -&gt; 12
127.0.0.1:6379&gt; NR.OBSERVE net 3 1 -&gt; 4
127.0.0.1:6379&gt; NR.OBSERVE net 5 6 -&gt; 11</pre>
<h5>トレーニング開始</h5>
<pre>127.0.0.1:6379&gt; NR.TRAIN net AUTOSTOP
Training has started</pre>
<h5>トレーニング結果のテスト</h5>
<p>比較的想定に近い結果が出ていることがわかります。</p>
<pre>127.0.0.1:6379&gt; NR.RUN net 1 1
1) "2.0505485534667969"
127.0.0.1:6379&gt; NR.RUN net 4 6
1) "10.419864654541016"
127.0.0.1:6379&gt; NR.RUN net 2 3
1) "4.8927350044250488"</pre>
<h4>neural-redis (2) 分類</h4>
<p>入力データをグループ分けする問題の例として、neural-redisにサンプルとして付属しているタイタニック号の乗客の生存予測を行います。</p>
<h5>モジュールに同梱されているサンプル</h5>
<ul>
<li>入力パラメータ: 乗客の各種属性(チケットクラス、性別、年齢、兄弟・親子の乗船数、チケット料金)</li>
<li>分類ラベル: 生存 or 死亡</li>
</ul>
<h5>付属のRubyスクリプトで学習データ(CSV形式)の投入とトレーニング</h5>
<pre>$ cd neural-redis/examples
$ ruby titanic.rb
Before training
185 prediction errors on 290 items
Still training...
After training
47 prediction errors on 290 items</pre>
<h5>トレーニング結果のテスト</h5>
<p>ファーストクラス、女性、30歳、兄弟・親子なしの場合、95%の確率で生存という結果になりました</p>
<pre>$ redis-cli
127.0.0.1:6379&gt; NR.RUN mynet 1 0 0 0 1 30 0 0 200
1) "0.066139459609985352"
2) "0.94962334632873535"</pre>
<p>年齢を70歳に上げた場合、95%から92.5%に減少しました。</p>
<pre>127.0.0.1:6379&gt; NR.RUN mynet 1 0 0 0 1 70 0 0 200
1) "0.08922017365694046"
2) "0.925819993019104"</pre>
<p>70歳、サードクラス、格安チケットのように条件を悪くした場合、生存率が32%と大幅に減少しました。</p>
<pre>127.0.0.1:6379&gt; NR.RUN mynet 0 0 1 0 1 70 0 0 20
1) "0.6508185863494873"
2) "0.32001861929893494"</pre>
<p>より高度な使い方は<a href="https://github.com/antirez/neural-redis">neural-redis</a>のgithubページを参照してください。</p>
<h3>RedisGraph</h3>
<p><a href="https://github.com/RedisGraph/RedisGraph">RedisGraph</a>はRedisにグラフDB機能を追加するモジュールです。グラフDBはグラフ構造に特化したDBのことです。グラフDBとしてメジャーな<a href="https://neo4j.com/">Neo4j</a>のグラフクエリー言語であるCypherを採用しており、Neo4jの利用経験があればすぐに使うことができます。<br />
RedisGraphはRedis Labs社によりRSALライセンスで配布されています。</p>
<p>RedisGraphのビルドはやや複雑なため、ここではDockerイメージを使用して実行します。</p>
<pre># docker run -p 6379:6379 -it --rm redislabs/redisgraph</pre>
<p>RedisGraphではGRAPH.QUERYコマンドに対してスキーマ名とCypherクエリー文字列を指定して使用します。簡単な使い方を以下に示します。</p>
<h4>グラフを作成</h4>
<p>例として人同士の関係をグラフとして作成してみます。以下はJohnの友人はFred、Lisaの友人はMaryという関係をグラフ化したものです。</p>
<pre>$ redis-cli
127.0.0.1:6379&gt; GRAPH.QUERY People
"CREATE (:Person {name:'John'})-[:friend]-&gt;(:Person {name:'Fred'}),
(:Person {name:'Lisa'})-[:friend]-&gt;(:Person {name:'Mary'})"
1) 1) "Labels added: 1"
2) "Nodes created: 4"
3) "Properties set: 4"
4) "Relationships created: 2"
5) "Query internal execution time: 3.208423 milliseconds"</pre>
<h4>クエリ実行</h4>
<p>上記で登録した人同士の関係のグラフから、Fred の友人を検索してみます。</p>
<pre>127.0.0.1:6379&gt; GRAPH.QUERY People
"MATCH (p1:Person)-[:friend]-&gt;(p2:Person)
WHERE p2.name = 'Fred'
RETURN p1.name, p2.name"
1) 1) "p1.name"
2) "p2.name"
2) 1) 1) "John"
2) "Fred"
3) 1) "Query internal execution time: 0.326652 milliseconds"</pre>
<p>条件にマッチした数をカウントすることもできます。以下ではMaryの友人の数をカウントしています。</p>
<pre>127.0.0.1:6379&gt; GRAPH.QUERY People
"MATCH (p1:Person)-[:friend]-&gt;(p2:Person {name:'Mary'})
RETURN count(p1)"
1) 1) "count(p1)"
2) 1) 1) (integer) 1
3) 1) "Query internal execution time: 0.290916 milliseconds"</pre>
<h2>まとめ</h2>
<p>今回はRedisモジュールについて紹介しました。RedisモジュールによりユーザーがRedisに対して自由に機能拡張を行うことができます。HA機能を含むRedisの既存の機能を利用してRedisモジュールを実装することができるため、Redisコア機能の恩恵が得られます。</p>
<p>現在既に様々な高機能なRedisモジュールが提供されており、今後も新しいRedisモジュールの登場が期待できます。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Redisストリームについて</title>
		<link>https://www.sraoss.co.jp/tech-blog/redis/redis-streams/</link>
		
		<dc:creator><![CDATA[山本 博之 (Hiroyuki Yamamoto)]]></dc:creator>
		<pubDate>Mon, 02 Sep 2019 04:00:33 +0000</pubDate>
				<category><![CDATA[Redis]]></category>
		<category><![CDATA[KVS]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=3750</guid>

					<description><![CDATA[RedisストリームはRedis 5で新しく追加されたデータ型です。 Apache Kafka に類似したメッセージ処理のためのパワフルな機能を持っており、様々な応用が可能です。 既存の類似の機能 最初にRedisのメッ ...]]></description>
										<content:encoded><![CDATA[<p><a href="https://redis.io/topics/streams-intro">Redisストリーム</a>はRedis 5で新しく追加されたデータ型です。 <a href="https://kafka.apache.org/">Apache Kafka</a> に類似したメッセージ処理のためのパワフルな機能を持っており、様々な応用が可能です。</p>
<p><span id="more-3750"></span></p>
<h2>既存の類似の機能</h2>
<p>最初にRedisのメッセージ処理に適した既存の機能をいくつか紹介します。</p>
<h3>Pub/Sub</h3>
<p>Redisは<a href="https://redis.io/topics/pubsub">Pub/Sub</a>メッセージング機能を提供しています。SUBSCRIBE および PUBLISH コマンドにより、 Publisher(発行者)が送信したメッセージを複数の Subscriber(購読者)が受信することができます。PublisherはSubscriberを知っている必要がなく、メッセージを受け取れないPublisherがあってもSubscriberは影響を受けません。ただし、メッセージは保存されないため、SUBSCRIBEしていない期間のメッセージを受け取ることはできません。</p>
<figure id="attachment_3761" aria-describedby="caption-attachment-3761" style="width: 500px" class="wp-caption aligncenter"><img fetchpriority="high" decoding="async" class="wp-image-3761" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-pubsub-1024x416.png" alt="" width="500" height="203" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-pubsub-1024x416.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-pubsub-300x122.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-pubsub-768x312.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-pubsub-304x123.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-pubsub-282x115.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-pubsub.png 1332w" sizes="(max-width: 500px) 100vw, 500px" /><figcaption id="caption-attachment-3761" class="wp-caption-text">Pub/Subモデル</figcaption></figure>
<h3>Blocked list</h3>
<p>Redisのリスト型はメッセージキューとして使うことができ、 <a href="https://redis.io/commands/BLPOP">BLPOP</a> および BRPOP コマンドにより、リストの先頭もしくは末尾からデータ(メッセージ)の到着を待って受信することができます。複数のクライアントが同時に受信を待つことができますが、1つのメッセージを受け取った時点でそのメッセージは削除されるので、1つのメッセージを受け取れるのは1つのクライアントのみとなります。</p>
<figure id="attachment_3777" aria-describedby="caption-attachment-3777" style="width: 600px" class="wp-caption aligncenter"><img decoding="async" class="wp-image-3777" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-blist-300x64.png" alt="" width="600" height="129" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-blist-300x64.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-blist-768x165.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-blist-1024x219.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-blist-304x65.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-blist-282x60.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-blist.png 1307w" sizes="(max-width: 600px) 100vw, 600px" /><figcaption id="caption-attachment-3777" class="wp-caption-text">Blocked list</figcaption></figure>
<h2>ストリームの特徴</h2>
<p>Redisストリームは前述のPub/SubおよびBlocked listに対して大幅に強化された機能をもちます。</p>
<p>Redisストリームは以下のような特徴があります。</p>
<ul>
<li>データを時系列で持つ追記型データ構造</li>
<li>各データは任意の複数のフィールドを持つことができる</li>
<li>データを取得しても過去のデータを残せる</li>
<li>時間の範囲を指定して複数のデータを読み出せる</li>
<li>コンシューマグループの概念によりクライアントをグループ化して協調動作できる</li>
</ul>
<figure id="attachment_3782" aria-describedby="caption-attachment-3782" style="width: 720px" class="wp-caption aligncenter"><img decoding="async" class="wp-image-3782" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-streams-1024x711.png" alt="" width="720" height="500" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-streams-1024x711.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-streams-300x208.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-streams-768x533.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-streams-304x211.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-streams-282x196.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/08/redis-streams.png 1376w" sizes="(max-width: 720px) 100vw, 720px" /><figcaption id="caption-attachment-3782" class="wp-caption-text">Redisストリーム</figcaption></figure>
<h2>ストリームのデータ構造</h2>
<p>Redisストリームのデータ構造自体は比較的シンプルです。</p>
<p>Redisストリームは追記専用のデータ構造です。各エントリは固有のIDを持ちます。IDは単調増加し、データ追加時にIDを指定しない場合は現在時刻から「&lt;タイムスタンプ&gt;-&lt;連番&gt;」の形式で自動生成されます。1つのエントリは任意の数のフィールドと値のペアで構成されます。</p>
<h2>使用例</h2>
<h3>監視データをストリームに保存することを想定した場合の例</h3>
<p>一定時間ごとに監視ツールで計測した監視データを時系列でストリームに保存するという用途を想定します。ここではストリームは単に時系列のデータ構造として使用し、1レコードにホストID、監視項目とその値を保存するものとします。</p>
<h4>データを追加</h4>
<p><a href="https://redis.io/commands/xadd">XADD</a>コマンドでストリーム名、ID、フィールド名と値を指定してデータを追加します。IDに「*」を指定するとIDを自動生成します。</p>
<pre>&gt; XADD history * hostid 1234 cpu.util 1.2
"1565915608548-0" (←自動生成されたID)
&gt; XADD history * hostid 1350 mem.used 65.3
"1565915613858-0" (←自動生成されたID)
...</pre>
<h4>全範囲のメッセージを取得</h4>
<p><a href="https://redis.io/commands/xrange">XRANGE</a>コマンドは指定した範囲のIDのデータを取得します。「-」は最小のID、「+」は最大のIDを意味するので、以下のコマンドはすべてのデータが取得されます。</p>
<pre>&gt; XRANGE history - +
1) 1) "1565915608548-0"
   2) 1) "hostid"
      2) "1234"
      3) "cpu.util"
      4) "1.2"
2) 1) "1565915613858-0"
   2) 1) "hostid"
      2) "1350"
      3) "mem.used"
      4) "65.3"</pre>
<h4>最初から1つ分のメッセージを取得</h4>
<p><a href="https://redis.io/commands/xread">XREAD</a>コマンドは指定したIDより大きいIDを持つデータを取得します。ID 0 (0-0)は最小のIDを意味するので、ストリームの最初からデータを取得することになります。COUNTオプションで一回で取得するデータの数を指定できます。</p>
<pre>&gt; XREAD COUNT 1 STREAMS history 0
1) 1) "1565915608548-0"
   2) 1) "hostid"
      2) "1234"
      3) "cpu.util"
      4) "1.2"</pre>
<h3>簡易チャットの例</h3>
<p>Slackのような複数チャンネルを持ち、過去の履歴も含めて参照可能なチャットシステムを簡易的に再現してみます。</p>
<h4>チャンネル作成、発言</h4>
<p>XADDコマンドでチャンネル名のストリームにメッセージを追加します。ストリームが存在しない場合は自動的に作成されます。格納するデータはメッセージ本体と発言者とします。</p>
<pre>&gt; XADD #channel * msg "channel #channel created."
"1565932257598-0"
&gt; XADD #channel * msg "こんにちは" user "Taro"
"1565932327972-0"
&gt; XADD #channel * msg "@Taro こんにちは!" user "Hanako"
"1565932387775-0"</pre>
<h4>新規に参加したユーザがチャンネルの最初からメッセージを取得</h4>
<p>XREADコマンドでチャンネルの最初からすべてのメッセージを取得します。</p>
<pre>&gt; XREAD STREAMS #channel 0
1) 1) "#channel"
   2) 1) 1) "1565932257598-0"
         2) 1) "msg"
            2) "channel #channel created."
      2) 1) "1565932327972-0"
         2) 1) "msg"
            2) "こんにちは"
            3) "user"
            4) "Taro"
      3) 1) "1565932387775-0"
         2) 1) "msg"
            2) "@Taro こんにちは!"
            3) "user"
            4) "Hanako"</pre>
<p>※UTF-8 文字列は実際にはエスケープされて出力されますが、分かりやすくするためそのまま記述しています。なお、redis-cliコマンドに&#8211;rawオプションを付けて起動するとそのまま出力できます。</p>
<h4>新着メッセージを待つ(タイムアウト60秒)</h4>
<p>XREADコマンドにBLOCKオプションを付けると、新しいメッセージが追加されるまで指定時間待ちます。IDに「$」を指定すると、XREADコマンドを発行した後に追加されたメッセージのみが対象となります。</p>
<pre>&gt; XREAD BLOCK 60000 STREAMS #channel $</pre>
<h4>誰かが60秒以内に発言する</h4>
<pre>&gt; XADD #channel * msg "Redis Streamsでチャットを作ってみたよ" user "Jiro"
"1565932616524-0"</pre>
<h4>XREAD BLOCK が返り、メッセージが取得される</h4>
<pre>1) 1) "#channel"
   2) 1) 1) "1565932616524-0"
         2) 1) "msg"
            2) "Redis Streamsでチャットを作ってみたよ"
            3) "user"
            4) "Jiro"
(2.75s)</pre>
<h4>次のメッセージを待つ(既にあれば即座に取得)</h4>
<p>連続してメッセージを取得する場合は前回取得した最後のIDを指定することに注意してください。再度「$」を指定してしまうと、途中のメッセージが抜け落ちる恐れがあります。</p>
<pre>&gt; XREAD BLOCK 60000 STREAMS #channel 1565932616524-0</pre>
<h3>監視データを複数クライアントで並列処理することを想定した場合の例</h3>
<p>1つめの例で保存した監視データをコンシューマグループを利用し、複数のクライアントで協調して処理することを想定します。</p>
<h4>ストリーム history に対してコンシューマグループ group1 を作成</h4>
<p><a href="https://redis.io/commands/xgroup">XGROUP</a>コマンドでコンシューマグループを作成します。IDに「0」を指定するとストリーム history の最初からデータを読み込みます。</p>
<pre>&gt; XGROUP CREATE history group1 0
OK</pre>
<h4>グループのメンバー C1 が他のメンバーによってまだ読まれていないデータを1つ読む</h4>
<p><a href="https://redis.io/commands/xreadgroup">XREADGROUP</a>コマンドでコンシューマグループを使用してデータを取得します。ここではコンシューマのメンバー「C1」としてデータを読みます。コンシューマがまだ存在しない場合は自動的に作成されます。IDに「&gt;」を指定すると、他のコンシューマに送信されていない新しいメッセージを要求します。</p>
<pre>&gt; XREADGROUP GROUP group1 C1 COUNT 1 STREAMS history &gt;
1) 1) "history"
   2) 1) 1) "1565915608548-0"
         2) 1) "hostid"
            2) "1234"
            3) "cpu.util"
            4) "1.2"</pre>
<h4>グループのメンバー C2 が他のメンバーによってまだ読まれていないデータを1つ読む</h4>
<p>続いてメンバーC2が同様にデータを取得します。先程C1により取得されたデータではなくその次のメッセージが返ります。</p>
<pre>&gt; XREADGROUP GROUP group1 C2 COUNT 1 STREAMS history &gt;
1) 1) "history"
   2) 1) 1) "1565915613858-0"
         2) 1) "hostid"
            2) "1350"
            3) "mem.used"
            4) "65.3"</pre>
<h4>C1 が取得したがペンディング状態のデータを確認</h4>
<p>XREADGROUPでIDに「0」を指定すると、そのメンバーが取得し、かつペンディングとなっている(XACKを返していない)データが返ります。</p>
<pre>&gt; XREADGROUP GROUP group1 C1 STREAMS history 0
1) 1) "history"
   2) 1) 1) "1565915608548-0"
         2) 1) "hostid"
            2) "1234"
            3) "cpu.util"
            4) "1.2"</pre>
<h4>取得したデータが正常に処理できたことを伝える</h4>
<p>コンシューマが取得したデータを正常に処理できたら、そのことをサーバに<a href="https://redis.io/commands/xack">XACK</a>コマンドで伝えることで一連の処理が完了します。XACKで指定したデータはペンディングエントリリストから削除されます。</p>
<pre>&gt; XACK history group1 1565915608548-0
(integer) 1</pre>
<pre>&gt; XREADGROUP GROUP group1 C1 STREAMS history 0
1) 1) "history"
2) (empty list or set)</pre>
<h4>さらにデータを読む</h4>
<p>以降も同様にメンバーC1、C2でデータを取得し、処理完了を通知します。</p>
<pre>&gt; XREADGROUP GROUP group1 C1 COUNT 1 STREAMS history &gt;
1) 1) "history"
   2) 1) 1) "1565933823472-0"
         2) 1) "hostid"
            2) "1234"
            3) "proc.num[httpd]"
            4) "5"
&gt; XREADGROUP GROUP group1 C2 COUNT 1 STREAMS history &gt;
1) 1) "history"
   2) 1) 1) "1565933855023-0"
         2) 1) "hostid"
            2) "1350"
            3) "cpu.util"
            4) "0.3"</pre>
<h4>読んだことを確認</h4>
<pre>&gt; XACK history group1 1565933823472-0
(integer) 1
&gt; XACK history group1 1565915613858-0 1565933855023-0
(integer)</pre>
<h2>おわりに</h2>
<p>今回はRedisストリームについて紹介しました。Redisストリームのデータ構造自体はシンプルですが、データにアクセスするための豊富な機能が用意されています。これにより、単純な時系列データの保存から大規模なメッセージングシステムまで、非常に柔軟な使い方が可能となっています。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RedisをPacemakerで冗長化する</title>
		<link>https://www.sraoss.co.jp/tech-blog/pacemaker/redis-pacemaker/</link>
		
		<dc:creator><![CDATA[山本 博之 (Hiroyuki Yamamoto)]]></dc:creator>
		<pubDate>Thu, 01 Aug 2019 04:10:26 +0000</pubDate>
				<category><![CDATA[Pacemaker]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[KVS]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=3233</guid>

					<description><![CDATA[本稿では、Pacemaker/Corosyncを使用してRedisのクラスタを構成する方法をご紹介します。 RedisはSentinelでマスター・スレーブ構成の管理を行うことができますが、最低3個のSentinelが必 ...]]></description>
										<content:encoded><![CDATA[<p>本稿では、Pacemaker/Corosyncを使用してRedisのクラスタを構成する方法をご紹介します。<br />
RedisはSentinelでマスター・スレーブ構成の管理を行うことができますが、最低3個のSentinelが必要になります。また、仮想IPについては自前でスクリプトを作成するなどの工夫が必要になります。</p>
<p><span id="more-3233"></span></p>
<p>2ノードで完結させたい場合や、その他のリソースもあわせて管理したい場合はPacemaker/Corosyncを使用するのが便利です。Pacemakerには標準でRedisのリソースエージェントが含まれているため、比較的容易にRedisのクラスタを構築することができます。</p>
<h3>前提</h3>
<p>以下の環境を前提とします。今回はOS標準のPacemakerを使用します。</p>
<ul>
<li>OS: CentOS 7.4</li>
<li>パッケージ:
<ul>
<li>redis-5.0.5-1.el7.remi</li>
<li>pacemaker-1.1.19-8.el7_6.4</li>
<li>corosync-2.4.3-4.el7</li>
</ul>
</li>
</ul>
<table>
<tbody>
<tr>
<th>ホスト名</th>
<th>IPアドレス</th>
</tr>
<tr>
<td>server1</td>
<td>192.168.237.101</td>
</tr>
<tr>
<td>server2</td>
<td>192.168.237.102</td>
</tr>
<tr>
<td>(VIP)</td>
<td>192.168.237.150</td>
</tr>
</tbody>
</table>
<p>RedisとPacemakerのクラスタ構成は以下のようになります。</p>
<figure id="attachment_3277" aria-describedby="caption-attachment-3277" style="width: 600px" class="wp-caption alignnone"><img loading="lazy" decoding="async" class="wp-image-3277" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/07/redis-pacemaker.png" alt="" width="600" height="400" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/07/redis-pacemaker.png 837w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/07/redis-pacemaker-300x200.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/07/redis-pacemaker-768x512.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/07/redis-pacemaker-304x203.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/07/redis-pacemaker-282x188.png 282w" sizes="auto, (max-width: 600px) 100vw, 600px" /><figcaption id="caption-attachment-3277" class="wp-caption-text">RedisとPacemakerの構成</figcaption></figure>
<h3>Pacemakerのインストールと初期設定</h3>
<p>両方のノードに必要なパッケージをインストールします。なお、Redisのインストールおよびマスター・スレーブレプリケーションの設定は完了しているものとします。</p>
<pre># yum install corosync pacemaker pcs fence-agents-all</pre>
<p>クラスタを新規作成します。</p>
<pre>server1# pcs cluster auth server1 server2 -u hacluster -p (haclusterユーザのパスワード) --force
server1# pcs cluster setup --name cluster1 server1 server2</pre>
<p>corosync.conf の quorum の設定に以下を追加します。これは2ノードクラスタで片方のノード単独で起動できるようにするために必要です(理由は後述します)。</p>
<pre>quorum {
    provider: corosync_votequorum
    two_node: 1
    wait_for_all: 0  ★追加
}</pre>
<p>クラスタを起動します。</p>
<pre>server1# pcs cluster start --all

server1# pcs status
Cluster name: cluster1
Stack: corosync
Current DC: server1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Mon Jul  1 16:57:00 2019
Last change: Mon Jul  1 16:56:58 2019 by root via cibadmin on server1

2 nodes configured
0 resources configured

Online: [ server1 server2 ]

No resources


Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled</pre>
<p>今回は動作確認のためSTONITHを無効化し、1回の障害検知でフェイルオーバーするように設定します。</p>
<pre># pcs property set stonith-enabled=false
# pcs resource defaults resource-stickiness=INFINITY migration-threshold=1</pre>
<h3>Pacemakerリソースの作成</h3>
<p>仮想IPリソースを作成します。</p>
<pre># pcs resource create VIP ocf:heartbeat:IPaddr2 
  ip=192.168.237.150 cidr_netmask=24 nic=eth1 
  op monitor interval=10s</pre>
<p>Redisのマスター・スレーブリソースを作成します。Pacemakerのマスター・スレーブリソースは、複数のノードに複製され、主従関係をもつリソースです。リソースエージェントは resource-agents パッケージに含まれる ocf:heartbeat:redis を使用します。以下の例では、redisリソースおよびそのマスター・スレーブリソースを一度に作成しています。マスター・スレーブリソースはデフォルトで「&lt;リソースID&gt;-master」(redis-master)という名前が付きます。</p>
<pre># pcs resource create redis ocf:heartbeat:redis 
  op start timeout=300s 
  op monitor interval=5s 
  op monitor interval=3s role=Master 
  master</pre>
<p>VIPリソースとRedisのマスター・スレーブリソースのマスター側を colocation 制約で同じサーバに結び付けます。</p>
<pre># pcs constraint colocation add VIP with master redis-master score=INFINITY
</pre>
<p>この時点でリソースは起動しますが、一度両ノードのPacemakerを停止します。設定中にリソースを起動させたくない場合は先に両ノードをスタンバイモード(pcs node standby/unstandby)にしておいてもよいです。</p>
<pre>server2# systemctl stop pacemaker
server1# systemctl stop pacemaker</pre>
<h3>クラスタの起動</h3>
<p>Masterにしたいノード(server1)でPacemakerを起動します。</p>
<pre>server1# systemctl start pacemaker
server1# pcs status
Cluster name: cluster1
Stack: corosync
Current DC: server1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Fri Jul 19 14:20:49 2019
Last change: Fri Jul 19 14:15:52 2019 by root via crm_attribute on server2

2 nodes configured
3 resources configured

Online: [ server1 ]
OFFLINE: [ server2 ]

Full list of resources:

 VIP    (ocf::heartbeat:IPaddr2):       <strong>Started server1</strong>
 Master/Slave Set: redis-master [redis]
     <strong>Masters: [ server1 ]</strong>
     Stopped: [ server2 ]

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled</pre>
<p>server1ですべてのリソースの起動が完了したことを確認したら、server2のPacemakerを起動します。</p>
<pre>server2# systemctl start pacemaker</pre>
<p>しばらく待ち、リソースの起動が正常に完了すると以下のようになります。</p>
<pre># pcs status
Cluster name: cluster1
Stack: corosync
Current DC: server1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Fri Jul 19 14:24:24 2019
Last change: Fri Jul 19 14:15:52 2019 by root via crm_attribute on server2

2 nodes configured
3 resources configured

Online: [ server1 server2 ]

Full list of resources:

 VIP    (ocf::heartbeat:IPaddr2):       <strong>Started server1</strong>
 Master/Slave Set: redis-master [redis]
     <strong>Masters: [ server1 ]</strong>
     <strong>Slaves: [ server2 ]</strong>

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled

# pcs constraint
Location Constraints:
Ordering Constraints:
Colocation Constraints:
  VIP with redis-master (score:INFINITY) (rsc-role:Started) (with-rsc-role:Master)
Ticket Constraints:</pre>
<p>Redisのレプリケーションが正常に行われていることを確認します。</p>
<pre>server1# redis-cli info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.237.102,port=6379,state=online,offset=1372,lag=0

server2# redis-cli info replication
# Replication
role:slave
master_host:server1
master_port:6379
master_link_status:up</pre>
<p>また、MasterノードにVIPが割り振られていることを確認します。</p>
<pre>server1# ip -4 addr show dev eth1
3: eth1: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.237.101/24 brd 192.168.237.255 scope global eth1
       valid_lft forever preferred_lft forever
    <strong>inet 192.168.237.150/24 brd 192.168.237.255 scope global secondary eth1</strong>
       valid_lft forever preferred_lft forever

server2# ip -4 addr show dev eth1
3: eth1: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.237.102/24 brd 192.168.237.255 scope global eth1
       valid_lft forever preferred_lft forever</pre>
<h3>フェイルオーバー</h3>
<p>RedisのMasterプロセスに障害を発生させ、server2がMasterになることを確認します。</p>
<pre>server1# killall redis-server
server1# pcs status
Cluster name: cluster1
Stack: corosync
Current DC: server1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Fri Jul 19 15:34:23 2019
Last change: Fri Jul 19 15:33:18 2019 by root via crm_attribute on server2

2 nodes configured
3 resources configured

Online: [ server1 server2 ]

Full list of resources:

 VIP    (ocf::heartbeat:IPaddr2):       <strong>Started server2</strong>
 Master/Slave Set: redis-master [redis]
     <strong>Masters: [ server2 ]</strong>
     Stopped: [ server1 ]

Failed Actions:
* redis_demote_0 on server1 'not running' (7): call=49, status=complete, exitreason='',
    last-rc-change='Fri Jul 19 15:33:18 2019', queued=0ms, exec=85ms


Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled</pre>
<p>redis リソースをクリーンアップし、server1がSlaveとして復旧することを確認します。</p>
<pre>server1# pcs resource cleanup redis
Cleaned up redis:0 on server2
Cleaned up redis:0 on server1
Cleaned up redis:1 on server2
Cleaned up redis:1 on server1
Waiting for 1 replies from the CRMd. OK

# pcs status resources
 VIP    (ocf::heartbeat:IPaddr2):       Started server2
 Master/Slave Set: redis-master [redis]
     Masters: [ server2 ]
     Slaves: [ server1 ]</pre>
<h3>リソース起動時の注意点</h3>
<p>Pacemaker/Corosyncの2ノードクラスタのデフォルトでは、両ノードのPacemakerが起動した時点でリソースを起動します。この場合、RedisのMasterとSlaveはほぼ同時に起動し、Masterの準備が完了していない状態でSlaveが接続しようとするため、レプリケーションの開始に失敗する場合があります。これを防ぐため、上記手順ではCorosyncの設定を変更し、Masterの起動を待ってからSlaveを起動するようにしています。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Redis Clusterについて</title>
		<link>https://www.sraoss.co.jp/tech-blog/redis/redis-cluster/</link>
		
		<dc:creator><![CDATA[山本 博之 (Hiroyuki Yamamoto)]]></dc:creator>
		<pubDate>Thu, 01 Aug 2019 04:05:41 +0000</pubDate>
				<category><![CDATA[Redis]]></category>
		<category><![CDATA[KVS]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=3047</guid>

					<description><![CDATA[前回のRedisの冗長化では、Redisの標準機能を用いてRedisの冗長化を行う方法についてご紹介しました。 今回はRedisでマルチマスター構成のクラスタを組むための機能であるRedis Clusterについてご紹介 ...]]></description>
										<content:encoded><![CDATA[<p>前回の<a href="https://www.sraoss.co.jp/tech-blog/redis/redis-ha/">Redisの冗長化</a>では、Redisの標準機能を用いてRedisの冗長化を行う方法についてご紹介しました。<br />
今回はRedisでマルチマスター構成のクラスタを組むための機能であるRedis Clusterについてご紹介します。</p>
<p><span id="more-3047"></span></p>
<h2>Redis Cluster</h2>
<p>Redis Cluster は Redis 3.0 で実装されました。Redis Cluster はマルチマスター構成をとり、データは複数のRedisサーバに自動的に分散されます(シャーディング)。これにより書き込み負荷を分散させることができます。Redis Cluster は一部のノードが故障しても動作を継続し、ある程度の可用性を提供しますが、多数のノードが利用不可となった場合は動作を停止します。各マスターノードにはスレーブを持たせ、可用性を向上することができます。クラスタの最小構成は3マスターノードとなります。</p>
<figure id="attachment_2995" aria-describedby="caption-attachment-2995" style="width: 520px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-2995" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-cluster-260x300.png" alt="" width="520" height="600" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-cluster-260x300.png 260w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-cluster-768x886.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-cluster-185x214.png 185w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-cluster-225x260.png 225w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-cluster.png 856w" sizes="auto, (max-width: 520px) 100vw, 520px" /><figcaption id="caption-attachment-2995" class="wp-caption-text">RedisのCluster構成</figcaption></figure>
<p>Clusterが使用するポートは通常のポートに加え、クラスタの通信用に+10000したポート番号を使用します(6379の場合は16739)。</p>
<h3>シャーディング</h3>
<p>Redis Cluster はクラスタ全体で16384個(0～16383)のhash slotをもちます。各ノードにhash slotの一部分が割り当てられます。例えば以下のようになります。</p>
<ul>
<li>ノードA: 0～5460 の hash slot</li>
<li>ノードB: 5461～10922 の hash slot</li>
<li>ノードC: 10923～16383 の hash slot</li>
</ul>
<p>クライアントがキーを登録するとき、キーごとにhash slotの値を計算し、対応するノードにデータが格納されます。キーからhash slotの値を求めるアルゴリズムは以下のようにシンプルなものとなります。</p>
<pre>HASH_SLOT = CRC16(key) mod 16384</pre>
<p>各ノードのhash slotは後から自由に移動することができるため、後からノードを追加したりノードを削除することが可能です。</p>
<h3>Cluster の設定</h3>
<p>本来は複数台のマシンで動作させますが、今回は1台のマシン上でポート番号を変えて6台の Cluster ノードを作成します。</p>
<table>
<tbody>
<tr>
<th>名前</th>
<th>ホスト名</th>
<th>IPアドレス</th>
<th>ポート</th>
<th>クラスタポート</th>
</tr>
<tr>
<td>Node 1</td>
<td>server1</td>
<td>192.168.1.1</td>
<td>7000</td>
<td>17000</td>
</tr>
<tr>
<td>Node 2</td>
<td>server1</td>
<td>192.168.1.1</td>
<td>7001</td>
<td>17001</td>
</tr>
<tr>
<td>Node 3</td>
<td>server1</td>
<td>192.168.1.1</td>
<td>7002</td>
<td>17002</td>
</tr>
<tr>
<td>Node 4</td>
<td>server1</td>
<td>192.168.1.1</td>
<td>7003</td>
<td>17003</td>
</tr>
<tr>
<td>Node 5</td>
<td>server1</td>
<td>192.168.1.1</td>
<td>7004</td>
<td>17004</td>
</tr>
<tr>
<td>Node 6</td>
<td>server1</td>
<td>192.168.1.1</td>
<td>7005</td>
<td>17005</td>
</tr>
</tbody>
</table>
<p>ノードごとに個別のディレクトリを作成し、既存の redis.conf をコピーして設定を行います。</p>
<pre># mkdir cluster-test
# cd cluster-test/
# mkdir 7000 7001 7002 7003 7004 7005
# cp /etc/redis.conf 7000
# vi 7000/redis.conf
# cp 7000/redis.conf 7001
# vi 7001/redis.conf
...
# vi 7005/redis.conf</pre>
<p>同サーバ上で動かすため、ファイル名が重複しないように適切に設定を行います。</p>
<pre>port 7000
pidfile "/var/run/redis_7000.pid"
logfile "/root/cluster-test/7000/redis.log"
dbfilename "dump-7000.rdb"
appendonly yes
appendfilename "appendonly-7000.aof"
cluster-enabled yes
cluster-config-file nodes-7000.conf</pre>
<p>各ノードを起動します。</p>
<pre># redis-server 7000/redis.conf
# redis-server 7001/redis.conf
# redis-server 7002/redis.conf
# redis-server 7003/redis.conf
# redis-server 7004/redis.conf
# redis-server 7005/redis.conf</pre>
<p>正常にプロセスが立ち上がり、 redis.log にエラーが出力されていないことを確認します。</p>
<pre># ps auxww|grep redis
root 2939 0.1 0.1 153952 2772 ? Ssl 14:23 0:00 redis-server 0.0.0.0:7000 [cluster]
root 2980 0.1 0.1 153952 2768 ? Ssl 14:24 0:00 redis-server 0.0.0.0:7001 [cluster]
root 2985 0.2 0.1 153952 2768 ? Ssl 14:24 0:00 redis-server 0.0.0.0:7002 [cluster]
root 2990 0.2 0.1 153952 2772 ? Ssl 14:24 0:00 redis-server 0.0.0.0:7003 [cluster]
root 2995 0.3 0.1 153952 2776 ? Ssl 14:25 0:00 redis-server 0.0.0.0:7004 [cluster]
root 3000 0.7 0.1 153952 2776 ? Ssl 14:25 0:00 redis-server 0.0.0.0:7005 [cluster]</pre>
<p>/var/lib/redis 以下に各ノードの AOF およびクラスタ設定ファイルが作成されます。</p>
<pre># ls -l /var/lib/redis/
合計 24
-rw-r--r--. 1 root root 0 6月 28 14:23 appendonly-7000.aof
-rw-r--r--. 1 root root 0 6月 28 14:24 appendonly-7001.aof
-rw-r--r--. 1 root root 0 6月 28 14:24 appendonly-7002.aof
-rw-r--r--. 1 root root 0 6月 28 14:25 appendonly-7003.aof
-rw-r--r--. 1 root root 0 6月 28 14:25 appendonly-7004.aof
-rw-r--r--. 1 root root 0 6月 28 14:25 appendonly-7005.aof
-rw-r--r--. 1 root root 114 6月 28 14:23 nodes-7000.conf
-rw-r--r--. 1 root root 114 6月 28 14:24 nodes-7001.conf
-rw-r--r--. 1 root root 114 6月 28 14:24 nodes-7002.conf
-rw-r--r--. 1 root root 114 6月 28 14:25 nodes-7003.conf
-rw-r--r--. 1 root root 114 6月 28 14:25 nodes-7004.conf
-rw-r--r--. 1 root root 114 6月 28 14:25 nodes-7005.conf</pre>
<p>次に、クラスタを作成します。 &#8211;cluster-replicas 1 はマスターごとに1つのレプリカ(スレーブ)を配置することを意味します。<br />
なお、 Redis 3.0、4.0 の場合は redis-cli の代わりに redis-trib.rb という外部ツールを使用する必要があります。</p>
<pre># redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 
127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 
--cluster-replicas 1</pre>
<p>自動的にマスターとレプリカの割り当てが行われます。よければ yes を入力します。</p>
<pre>&gt;&gt;&gt; Performing hash slots allocation on 6 nodes...
Master[0] -&gt; Slots 0 - 5460
Master[1] -&gt; Slots 5461 - 10922
Master[2] -&gt; Slots 10923 - 16383
Adding replica 127.0.0.1:7004 to 127.0.0.1:7000
Adding replica 127.0.0.1:7005 to 127.0.0.1:7001
Adding replica 127.0.0.1:7003 to 127.0.0.1:7002
&gt;&gt;&gt; Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000
slots:[0-5460] (5461 slots) master
M: a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001
slots:[5461-10922] (5462 slots) master
M: a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002
slots:[10923-16383] (5461 slots) master
S: 4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003
replicates a5b82da0c32957954a3da1e16a3629083a8d5d8c
S: 04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004
replicates a18a55b7a4790c2bd1bd7fae057caa4144a03a52
S: 0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005
replicates 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111
Can I set the above configuration? (type 'yes' to accept): <strong>yes</strong>
&gt;&gt;&gt; Nodes configuration updated
&gt;&gt;&gt; Assign a different config epoch to each node
&gt;&gt;&gt; Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
&gt;&gt;&gt; Performing Cluster Check (using node 127.0.0.1:7000)
M: 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005
slots: (0 slots) slave
replicates 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111
S: 04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004
slots: (0 slots) slave
replicates a18a55b7a4790c2bd1bd7fae057caa4144a03a52
M: a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
M: a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003
slots: (0 slots) slave
replicates a5b82da0c32957954a3da1e16a3629083a8d5d8c
[OK] All nodes agree about slots configuration.
&gt;&gt;&gt; Check for open slots...
&gt;&gt;&gt; Check slots coverage...
[OK] All 16384 slots covered.</pre>
<p>クラスタの構成が正常に完了すると [OK] All 16384 slots covered. というメッセージが出力されます。<br />
なお、マスターとレプリカの組み合わせを自分で決定したい場合は、<br />
最初にマスターのみでクラスタを構成した後、マスターを指定してレプリカを1つずつ追加していきます。</p>
<pre># redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002

# redis-cli --cluster add-node 127.0.0.1:7003 127.0.0.1:7000 --cluster-slave --cluster-master-id 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111
# redis-cli --cluster add-node 127.0.0.1:7004 127.0.0.1:7001 --cluster-slave --cluster-master-id a5b82da0c32957954a3da1e16a3629083a8d5d8c
# redis-cli --cluster add-node 127.0.0.1:7005 127.0.0.1:7002 --cluster-slave --cluster-master-id a18a55b7a4790c2bd1bd7fae057caa4144a03a52</pre>
<p>任意のノードに redis-cli で接続し、 cluster nodes コマンドを実行するとノードの一覧を取得することができます。これは nodes-7000.conf とほぼ同じ内容になります。</p>
<pre># redis-cli -p 7000 cluster nodes
0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005@17005 slave 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 0 1561702297172 6 connected
70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000@17000 myself,master - 0 1561702298000 1 connected 0-5460
04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004@17004 slave a18a55b7a4790c2bd1bd7fae057caa4144a03a52 0 1561702299186 5 connected
a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001@17001 master - 0 1561702296161 2 connected 5461-10922
a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002@17002 master - 0 1561702298000 3 connected 10923-16383
4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003@17003 slave a5b82da0c32957954a3da1e16a3629083a8d5d8c 0 1561702298181 4 connected</pre>
<h3>Clusterの動作確認</h3>
<p>redis-cli に -c を付けるとクラスタモードになります。これで動作を確認します。</p>
<pre># redis-cli -c -p 7000
127.0.0.1:7000&gt; set foo 1
-&gt; Redirected to slot [12182] located at 127.0.0.1:7002
OK
127.0.0.1:7002&gt; get foo
"1"
127.0.0.1:7002&gt; set bar 2
-&gt; Redirected to slot [5061] located at 127.0.0.1:7000
OK
127.0.0.1:7000&gt; get bar
"2"
127.0.0.1:7000&gt; get foo
-&gt; Redirected to slot [12182] located at 127.0.0.1:7002
"1"
127.0.0.1:7002&gt; get hoge
-&gt; Redirected to slot [1525] located at 127.0.0.1:7000
(nil)
127.0.0.1:7000&gt; incr foo
-&gt; Redirected to slot [12182] located at 127.0.0.1:7002
(integer) 2
127.0.0.1:7002&gt; get foo
"2"</pre>
<p>キーに応じてslotが変化し、対応するノードに自動的に接続を切り替えていることがわかります。</p>
<h3>Clusterのクエリの制限</h3>
<p>Clusterではキーごとに格納されるノードが異なるため、クライアント側でキーに対応するノードを知る必要があります(対応するノードはサーバから通知されます)。また、キーが複数のノードにまたがっている場合、複数のキーをまとめて取得する mget のようなコマンドは失敗します。</p>
<p>複数のキーを同じノードに割り当てたい場合、ハッシュタグ({ } で囲まれた文字列)を利用することができます。キーの一部に {&#8230;} という文字列を含めることで、 { } 内の文字列のみが hash slot の計算に使用されるようになります。以下の2つのキーは同一の hash slot となり、同じノードに格納されます。</p>
<pre>{foo}hoge
{foo}fuga</pre>
<h3>フェイルオーバー</h3>
<p>7000番ポートのmasterに障害を発生させます。</p>
<pre># kill 2939
# ps auxww|grep redis
root 2980 0.1 0.1 156512 3256 ? Ssl 14:24 0:07 redis-server 0.0.0.0:7001 [cluster]
root 2985 0.1 0.1 158560 3284 ? Ssl 14:24 0:07 redis-server 0.0.0.0:7002 [cluster]
root 2990 0.2 0.2 167264 4144 ? Ssl 14:24 0:07 redis-server 0.0.0.0:7003 [cluster]
root 2995 0.2 0.1 160608 3372 ? Ssl 14:25 0:07 redis-server 0.0.0.0:7004 [cluster]
root 3000 0.2 0.1 160608 3376 ? Ssl 14:25 0:07 redis-server 0.0.0.0:7005 [cluster]</pre>
<p>cluster nodes の表示が fail となります。</p>
<pre># redis-cli -p 7001 cluster nodes
70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000@17000 <strong>master,fail</strong> - 1561703162227 1561703160916 1 disconnected 0-5460
a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001@17001 myself,master - 0 1561703190000 2 connected 5461-10922
a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002@17002 master - 0 1561703189000 3 connected 10923-16383
04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004@17004 slave a18a55b7a4790c2bd1bd7fae057caa4144a03a52 0 1561703190193 3 connected
0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005@17005 slave 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 0 1561703189185 1 connected
4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003@17003 slave a5b82da0c32957954a3da1e16a3629083a8d5d8c 0 1561703188000 4 connected</pre>
<p>しばらくすると自動的に7000番ポートのmasterのslaveである7005番ポートのノードがmasterに昇格し、フェイルオーバーが完了します。</p>
<pre># redis-cli -p 7001 cluster nodes
70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000@17000 master,fail - 1561703162227 1561703160916 1 disconnected
a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001@17001 myself,master - 0 1561703238000 2 connected 5461-10922
a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002@17002 master - 0 1561703240648 3 connected 10923-16383
04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004@17004 slave a18a55b7a4790c2bd1bd7fae057caa4144a03a52 0 1561703242665 3 connected
0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005@17005 <strong>master</strong> - 0 1561703242000 8 connected 0-5460
4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003@17003 slave a5b82da0c32957954a3da1e16a3629083a8d5d8c 0 1561703240000 4 connected</pre>
<p>7000番ポートのRedisを再度起動すると、7005番ポートのmasterのslaveとして立ち上がり、再同期が行われます。</p>
<pre># redis-server 7000/redis.conf
# redis-cli -p 7001 cluster nodes
70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000@17000 <strong>slave</strong> 0a0dfeb8456c6bff470eddb24edae8743d6422ff 0 1561703557658 8 connected
a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001@17001 myself,master - 0 1561703558000 2 connected 5461-10922
a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002@17002 master - 0 1561703559675 3 connected 10923-16383
04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004@17004 slave a18a55b7a4790c2bd1bd7fae057caa4144a03a52 0 1561703556649 3 connected
0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005@17005 master - 0 1561703558000 8 connected 0-5460
4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003@17003 slave a5b82da0c32957954a3da1e16a3629083a8d5d8c 0 1561703558667 4 connected</pre>
<h2>おわりに</h2>
<p>今回はRedisの標準機能の一つであるRedis Clusterについて紹介しました。Redis Clusterは必要なサーバ台数が多くなるものの、負荷分散と可用性を両立させることができます。</p>
<p>次回はPacemakerを用いたRedisの冗長化について紹介します。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Redisの冗長化</title>
		<link>https://www.sraoss.co.jp/tech-blog/redis/redis-ha/</link>
		
		<dc:creator><![CDATA[基盤技術グループ]]></dc:creator>
		<pubDate>Thu, 01 Aug 2019 04:00:08 +0000</pubDate>
				<category><![CDATA[Redis]]></category>
		<category><![CDATA[KVS]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=2968</guid>

					<description><![CDATA[本稿では、Redis標準のReplicationおよびSentinel機能について解説します。 Redisの可用性を高めるための方法として、以下の3つの機能が標準で用意されています。 Replication: マスター・ ...]]></description>
										<content:encoded><![CDATA[<p>本稿では、Redis標準のReplicationおよびSentinel機能について解説します。</p>
<p>Redisの可用性を高めるための方法として、以下の3つの機能が標準で用意されています。</p>
<ul>
<li>Replication: マスター・スレーブ型のレプリケーション</li>
<li>Sentinel: 死活監視と自動フェイルオーバーを行うサービス</li>
<li>Cluster: マルチマスター構成。データを複数サーバに分散できる(シャーディング)</li>
</ul>
<p><span id="more-2968"></span></p>
<p>その他の方法としてはPacemaker/Corosync、keepalived、HAProxy等を組み合わせて使うことができます。Pacemakerには<a href="https://github.com/ClusterLabs/resource-agents/blob/master/heartbeat/redis.in">Redisのリソースエージェント</a>が同梱されています。</p>
<p>&nbsp;</p>
<h2>Replication</h2>
<p>Redis は標準でマスター・スレーブ型のレプリケーションによる冗長構成をとることができます。Redis は非同期レプリケーションを採用しています。マスターは複数のスレーブを持つことができます。スレーブも読み込みクエリを受け付けることができるため、負荷分散目的でも使用することができます。</p>
<figure id="attachment_2991" aria-describedby="caption-attachment-2991" style="width: 604px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-2991" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-replication-300x57.png" alt="" width="604" height="114" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-replication-300x57.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-replication-768x145.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-replication-304x57.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-replication-282x53.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-replication.png 837w" sizes="auto, (max-width: 604px) 100vw, 604px" /><figcaption id="caption-attachment-2991" class="wp-caption-text">RedisのReplication構成</figcaption></figure>
<p>なお、 Replication 機能自体はマスター障害時の自動フェイルオーバー機能などは持っていないため、自動フェイルオーバーを行うには後述する Sentinel 、もしくは Pacemaker/Corosync、keepalived などの他のクラスタ管理ソフトウェアを使用する必要があります。</p>
<h3>レプリケーションの設定</h3>
<p>以下の構成でレプリケーションの設定を行います。</p>
<table>
<tbody>
<tr>
<th>名前</th>
<th>ホスト名</th>
<th>IPアドレス</th>
<th>ポート</th>
</tr>
<tr>
<td>Master</td>
<td>server1</td>
<td>192.168.1.1</td>
<td>6379</td>
</tr>
<tr>
<td>Slave</td>
<td>server2</td>
<td>192.168.1.2</td>
<td>6379</td>
</tr>
</tbody>
</table>
<p>他ホストからの接続を受け付けるよう、マスターおよびスレーブの redis.conf を修正します。</p>
<pre># vi /etc/redis.conf
bind 127.0.0.1 -&gt; bind 127.0.0.1 192.168.1.1 192.168.1.2</pre>
<p>Redis をスレーブとして動作させるには、 redis.conf に slaveof &lt;マスターのIPアドレス&gt; &lt;ポート番号&gt; を追加し、 Redis を再起動します。</p>
<pre>slaveof 192.168.1.1 6379</pre>
<p>もしくは redis-cli で SLAVEOF コマンドを発行してもよいです。</p>
<pre>127.0.0.1:6379&gt; slaveof 192.168.1.1 6379</pre>
<p>スレーブ側でredis-cli info replicationコマンドを実行し、スレーブとして動作していることを確認します。</p>
<pre>server2# redis-cli info replication
# Replication
role:slave
master_host:192.168.1.1
master_port:6379
master_link_status:up
...</pre>
<p>マスター側でも実行し、スレーブが認識されていることを確認します。</p>
<pre>server1# redis-cli info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.1.2,port=6379,state=online,offset=294,lag=1
...</pre>
<p>マスターでキーを登録し、スレーブに反映されていることを確認します。</p>
<pre>Master&gt; set repl-test 10000
OK

Slave&gt; get repl-test
"10000"

Master&gt; incr repl-test
(integer) 10001

Slave&gt; get repl-test
"10001"</pre>
<p>デフォルトでスレーブは read-only モードで動作します。参照は可能ですが書き込むことはできません。</p>
<pre>Slave&gt; incr repl-test
(error) READONLY You can't write against a read only replica.</pre>
<h2>Sentinel</h2>
<p>Sentinel はマスターとスレーブの死活監視を行い、障害が発生した際に自動フェイルオーバーを行う機能です。<br />
マスター・スレーブ構成の2台以上の Redis サーバに対し、 Sentinel 3台以上で管理を行います。Sentinel は Redis サーバと同居させても、別のノード(クライアント等)で動作させても構いません。Sentinel は多数決によりフェイルオーバーを行うかどうかを決定します。</p>
<figure id="attachment_2992" aria-describedby="caption-attachment-2992" style="width: 598px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-2992" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-sentinel-300x138.png" alt="" width="598" height="275" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-sentinel-300x138.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-sentinel-768x353.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-sentinel-304x140.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-sentinel-282x130.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2019/06/redis-sentinel.png 903w" sizes="auto, (max-width: 598px) 100vw, 598px" /><figcaption id="caption-attachment-2992" class="wp-caption-text">RedisのSentinel構成</figcaption></figure>
<p>なお、 Sentinel 2台という構成はとることができません。これは片方の Sentinel がダウンした場合に残りの Sentinel が過半数(quorum)を獲得することができなくなるためです。</p>
<h3>Sentinel の設定</h3>
<p>前述の Replication 構成に Sentinel を追加します。<br />
Sentinel は3つあればどこで動かしてもよいですが、今回はシンプルにするため1台のSlaveマシン上でポート番号を変えて3つのSentinelを動かします。実際に運用する場合は3台の別々のマシンで動作させてください。</p>
<table>
<tbody>
<tr>
<th>名前</th>
<th>ホスト名</th>
<th>IPアドレス</th>
<th>ポート</th>
</tr>
<tr>
<td>Master</td>
<td>server1</td>
<td>192.168.1.1</td>
<td>6379</td>
</tr>
<tr>
<td>Slave</td>
<td>server2</td>
<td>192.168.1.2</td>
<td>6379</td>
</tr>
<tr>
<td>Sentinel 1</td>
<td>server2</td>
<td>192.168.1.2</td>
<td>26379</td>
</tr>
<tr>
<td>Sentinel 2</td>
<td>server2</td>
<td>192.168.1.2</td>
<td>26380</td>
</tr>
<tr>
<td>Sentinel 3</td>
<td>server2</td>
<td>192.168.1.2</td>
<td>26381</td>
</tr>
</tbody>
</table>
<p>Sentinel 用の設定ファイルを3台分コピーします。</p>
<pre># cd /etc/
# cp redis-sentinel.conf redis-sentinel-26379.conf
# cp redis-sentinel.conf redis-sentinel-26380.conf
# cp redis-sentinel.conf redis-sentinel-26381.conf</pre>
<p>各設定ファイルについて、最低限以下の設定を行います。</p>
<pre>protected-mode no
port &lt;Sentinelのポート番号&gt;
daemonize yes
pidfile /var/run/redis-sentinel-&lt;Sentinelのポート番号&gt;.pid
logfile /var/log/redis/sentinel-&lt;Sentinelのポート番号&gt;.log
sentinel monitor mymaster 192.168.1.1 6379 2</pre>
<p>Sentinel を起動します。</p>
<pre># redis-sentinel /etc/redis-sentinel-26379.conf
# redis-sentinel /etc/redis-sentinel-26380.conf
# redis-sentinel /etc/redis-sentinel-26381.conf</pre>
<p>ログファイル /var/log/redis/sentinel-&lt;Sentinelのポート番号&gt;.log に Master および他の Sentinel の情報が出力されていることを確認します。</p>
<pre>2103:X 27 Jun 2019 15:56:54.718 # Sentinel ID is 5d34898e3b273c93a45aa80d6bcce659cb7c3b04
2103:X 27 Jun 2019 15:56:54.718 # +monitor master mymaster 192.168.1.1 6379 quorum 2
2073:X 27 Jun 2019 15:56:54.719 * +slave slave 192.168.1.2:6379 192.168.1.2 6379 @ mymaster 192.168.1.1 6379
2103:X 27 Jun 2019 15:57:18.722 * +sentinel sentinel 3132314ff9ab580fb8ed83e34a24d724e104d4ac 192.168.1.2 26380 @ mymaster 192.168.1.1 6379
2103:X 27 Jun 2019 15:57:37.034 * +sentinel sentinel bf5642a065425c23dcaff16cb749c7556379c317 192.168.1.2 26381 @ mymaster 192.168.1.1 6379</pre>
<p>Master、Slave、Sentinelのプロセスが動作していることを確認します。</p>
<pre>Master# ps auxww | grep redis
redis 1219 0.1 0.2 159584 4460 ? Ssl 11:14 0:31 /usr/bin/redis-server 0.0.0.0:6379

Slave# ps auxww | grep redis
redis 2052 0.2 1.6 167204 16428 ? Ssl 15:44 0:03 /usr/bin/redis-server 0.0.0.0:6379
root 2103 0.3 0.7 153892 7808 ? Ssl 15:56 0:01 redis-sentinel *:26379 [sentinel]
root 2111 0.3 0.7 153892 7816 ? Ssl 15:57 0:01 redis-sentinel *:26380 [sentinel]
root 2119 0.3 0.7 153892 7776 ? Ssl 15:57 0:01 redis-sentinel *:26381 [sentinel]</pre>
<h3>フェイルオーバー</h3>
<p>Masterのredis-serverプロセスに障害を発生させます。</p>
<pre>Master# killall redis-server
# ps auxww | grep redis</pre>
<p>Sentinelのログを確認し、フェイルオーバーが行われたことを確認します。</p>
<p>Sentinelがノードの障害を検知するとSDOWN (Subjectively Down)状態に移行します。複数のSentinelがSDOWN状態となり、quorumの数を満たすとODOWN (Objectively Down)状態に移行し、フェイルオーバーが開始されます。フェイルオーバーを実行するSentinelは投票により決定されます。今回は 26381 番ポートの Sentinel がリーダーとして選出され、フェイルオーバーを実行しました。</p>
<pre>2119:X 27 Jun 2019 16:08:25.571 # +sdown master mymaster 192.168.1.1 6379
2119:X 27 Jun 2019 16:08:25.662 # +odown master mymaster 192.168.1.1 6379 #quorum 2/2
2119:X 27 Jun 2019 16:08:25.662 # +new-epoch 1
2119:X 27 Jun 2019 16:08:25.663 # +try-failover master mymaster 192.168.1.1 6379
2119:X 27 Jun 2019 16:08:25.666 # +vote-for-leader bf5642a065425c23dcaff16cb749c7556379c317 1
2119:X 27 Jun 2019 16:08:25.670 # 5d34898e3b273c93a45aa80d6bcce659cb7c3b04 voted for bf5642a065425c23dcaff16cb749c7556379c317 1
2119:X 27 Jun 2019 16:08:25.671 # 3132314ff9ab580fb8ed83e34a24d724e104d4ac voted for bf5642a065425c23dcaff16cb749c7556379c317 1
2119:X 27 Jun 2019 16:08:25.733 # +elected-leader master mymaster 192.168.1.1 6379
2119:X 27 Jun 2019 16:08:25.733 # +failover-state-select-slave master mymaster 192.168.1.1 6379
2119:X 27 Jun 2019 16:08:25.800 # +selected-slave slave 192.168.1.2:6379 192.168.1.2 6379 @ mymaster 192.168.1.1 6379
2119:X 27 Jun 2019 16:08:25.800 * +failover-state-send-slaveof-noone slave 192.168.1.2:6379 192.168.1.2 6379 @ mymaster 192.168.1.1 6379
2119:X 27 Jun 2019 16:08:25.867 * +failover-state-wait-promotion slave 192.168.1.2:6379 192.168.1.2 6379 @ mymaster 192.168.1.1 6379
2119:X 27 Jun 2019 16:08:25.874 # +promoted-slave slave 192.168.1.2:6379 192.168.1.2 6379 @ mymaster 192.168.1.1 6379
2119:X 27 Jun 2019 16:08:25.874 # +failover-state-reconf-slaves master mymaster 192.168.1.1 6379
2119:X 27 Jun 2019 16:08:25.939 # +failover-end master mymaster 192.168.1.1 6379
2119:X 27 Jun 2019 16:08:25.939 # +switch-master mymaster 192.168.1.1 6379 192.168.1.2 6379
2119:X 27 Jun 2019 16:08:25.939 * +slave slave 192.168.1.1:6379 192.168.1.1 6379 @ mymaster 192.168.1.2 6379
2119:X 27 Jun 2019 16:08:55.994 # +sdown slave 192.168.1.1:6379 192.168.1.1 6379 @ mymaster 192.168.1.2 6379</pre>
<p>Slaveとして動作していたRedisがマスターに昇格していることを確認します。</p>
<pre># redis-cli info replication
# Replication
role:master
connected_slaves:0</pre>
<p>元Masterを再起動すると、自動的に設定がSlaveに変更され、再同期が行われます。</p>
<pre># systemctl start redis
# ps auxww | grep redis
redis 4926 0.5 0.2 156512 4156 ? Ssl 16:37 0:00 /usr/bin/redis-server 0.0.0.0:6379

# less /var/log/redis/redis.log

4926:S 27 Jun 2019 16:37:26.415 * Before turning into a replica, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
4926:S 27 Jun 2019 16:37:26.416 * REPLICAOF 192.168.1.2:6379 enabled (user request from 'id=3 addr=192.168.1.2:46079 fd=8 name=sentinel-5d34898e-cmd age=10 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=155 qbuf-free=32613 obl=36 oll=0 omem=0 events=r cmd=exec')
4926:S 27 Jun 2019 16:37:26.417 # CONFIG REWRITE executed with success.
4926:S 27 Jun 2019 16:37:27.110 * Connecting to MASTER 192.168.1.2:6379
4926:S 27 Jun 2019 16:37:27.110 * MASTER &lt;-&gt; REPLICA sync started
4926:S 27 Jun 2019 16:37:27.110 * Non blocking connect for SYNC fired the event.
4926:S 27 Jun 2019 16:37:27.111 * Master replied to PING, replication can continue...
4926:S 27 Jun 2019 16:37:27.111 * Trying a partial resynchronization (request 428e1658f7baea92e543dce299ee9c4769e37729:1).
4926:S 27 Jun 2019 16:37:27.140 * Full resync from master: e006bbaf56f0298b1f022d037290ba9a65a75850:517729
4926:S 27 Jun 2019 16:37:27.141 * Discarding previously cached master state.
4926:S 27 Jun 2019 16:37:27.187 * MASTER &lt;-&gt; REPLICA sync: receiving 14785 bytes from master
4926:S 27 Jun 2019 16:37:27.187 * MASTER &lt;-&gt; REPLICA sync: Flushing old data
4926:S 27 Jun 2019 16:37:27.188 * MASTER &lt;-&gt; REPLICA sync: Loading DB in memory
4926:S 27 Jun 2019 16:37:27.188 * MASTER &lt;-&gt; REPLICA sync: Finished with success</pre>
<p>元Masterがスレーブとして動作していることを確認します。</p>
<pre># redis-cli info replication
# Replication
role:slave
master_host:192.168.1.2
master_port:6379
master_link_status:up</pre>
<p>現Slave(元Master)の redis.conf も自動的に書き換えられています。</p>
<pre># cat /etc/redis.conf
...
# Generated by CONFIG REWRITE
replicaof 192.168.1.2 6379</pre>
<h3>仮想IPの利用</h3>
<p>Sentinelは自動でフェイルオーバーを行ってくれますが、標準では仮想IPを付与するような機能はありませんので、クライアントは複数のサーバのIPアドレスと、どちらがMasterであるかを把握している必要があります。<br />
常にMasterに固定の仮想IPを割り振りたい場合は以下の方法があります。</p>
<h4>フェイルオーバー時のスクリプトの呼び出し</h4>
<p>Sentinelに以下の設定を行うとフェイルオーバー時にスクリプトを呼び出すことができます。スクリプトは各Sentinelサーバ上で実行されますので、SentinelをMasterサーバおよびSlaveサーバと同居させておく必要があります。</p>
<pre>sentinel client-reconfig-script mymaster /var/lib/redis/redis-vip.sh</pre>
<p>スクリプトに渡される引数は以下になります。今回はフェイルオーバー後のMasterのIPアドレス &lt;to-ip&gt; のみ使用します。</p>
<pre>&lt;master-name&gt; &lt;role&gt; &lt;state&gt; &lt;from-ip&gt; &lt;from-port&gt; <strong>&lt;to-ip&gt;</strong> &lt;to-port&gt;</pre>
<p>MasterおよびSlaveに /var/lib/redis/redis-vip.sh として以下のスクリプトを配置します。自ホストのIP等は各サーバに合わせます。それ以外のSentinelサーバではclient-reconfig-scriptの設定を無効にしておくか、ダミーのスクリプトを配置しておきます。</p>
<pre>#!/bin/sh

MASTER_IP=${6}
MY_IP='&lt;自ホストのIP&gt;'
VIP='&lt;仮想IP&gt;'
NETMASK='&lt;仮想IPのネットマスク&gt;'
INTERFACE='&lt;仮想IPを付与するNIC&gt;'

if [ ${MASTER_IP} = ${MY_IP} ]; then
        /sbin/ip addr add ${VIP}/${NETMASK} dev ${INTERFACE}
        /sbin/arping -q -c 3 -A ${VIP} -I ${INTERFACE}
        exit 0
else
        /sbin/ip addr del ${VIP}/${NETMASK} dev ${INTERFACE}
        exit 0
fi
exit 1</pre>
<p>なお、Redis起動時には上記スクリプトは実行されないので、初回のみ手動で実行してMasterに仮想IPを付与する必要があります。</p>
<pre>server1# /var/lib/redis/redis-vip.sh mymaster 0 0 0 0 &lt;MasterのIPアドレス&gt; 6379

server1# ip -4 a show dev ens192
2: ens192: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.1.1/24 brd 192.168.1.255 scope global dynamic ens192
       valid_lft 9311sec preferred_lft 9311sec
<strong>    inet &lt;仮想IP&gt; scope global secondary ens192</strong>
       valid_lft forever preferred_lft forever

server2# ip -4 a show dev ens192
2: ens192: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.1.2/24 brd 192.168.1.255 scope global dynamic ens192
       valid_lft 11155sec preferred_lft 11155sec</pre>
<p>Master (server1)のredis-serverプロセスを停止し、フェイルオーバーを発生させてみます。</p>
<pre>server1# killall redis-server</pre>
<p>元Slaveのserver2がMasterに昇格し、仮想IPが移動していることを確認します。</p>
<pre>server1# ip -4 a show dev ens192
2: ens192: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.1.1/24 brd 192.168.1.255 scope global dynamic ens192
       valid_lft 9311sec preferred_lft 9311sec

server2# redis-cli info replication
# Replication
role:master
connected_slaves:0

server2# ip -4 a show dev ens192
2: ens192: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.1.2/24 brd 192.168.1.255 scope global dynamic ens192
       valid_lft 11155sec preferred_lft 11155sec
<strong>    inet &lt;仮想IP&gt; scope global secondary ens192</strong>
       valid_lft forever preferred_lft forever</pre>
<h2>おわりに</h2>
<p>今回は、Redisの標準機能を用いてRedisの冗長化を行う方法について解説しました。Redisは標準機能のみで非常に柔軟に分散・冗長構成をとることができ、ニーズにあわせた様々な構成が考えられます。</p>
<p>次回はRedis Cluster機能について紹介します。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Redisのデータ永続化</title>
		<link>https://www.sraoss.co.jp/tech-blog/redis/redis-persistdata/</link>
		
		<dc:creator><![CDATA[山本 博之 (Hiroyuki Yamamoto)]]></dc:creator>
		<pubDate>Mon, 24 Jun 2019 01:00:19 +0000</pubDate>
				<category><![CDATA[Redis]]></category>
		<category><![CDATA[KVS]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=2728</guid>

					<description><![CDATA[インメモリDBとデータの永続化 前回のRedisの紹介では、Redisの特長や導入手順、基本的な使い方についてご紹介しました。本稿では、インメモリデータベースのデータ永続化についてご紹介します。 Redisはインメモリデ ...]]></description>
										<content:encoded><![CDATA[<h2>インメモリDBとデータの永続化</h2>
<p>前回の<a href="https://www.sraoss.co.jp/tech-blog/redis/redis-introduction/">Redisの紹介</a>では、Redisの特長や導入手順、基本的な使い方についてご紹介しました。本稿では、インメモリデータベースのデータ永続化についてご紹介します。</p>
<p>Redisはインメモリデータベースであるため、サーバプロセスが終了するとメモリ上のデータも消えてしまいます。そこで、Redisはサーバプロセス終了後もデータを保持するための2種類の機能が用意されています。</p>
<p><span id="more-2728"></span></p>
<h3>RDB</h3>
<p>Redisでは特定の時点のスナップショットをRDBファイルとして保存することができます。RDBはデータベースのダンプファイルに相当します。SAVEコマンドおよびBGSAVEコマンドで現時点のスナップショットを保存できます。また、設定により、一定の書き込み数と時間の経過により自動的にデータを保存することもできます。デフォルトの設定は以下のようになっており、条件を満たした場合にデータが自動保存されます。なお、「save &#8220;&#8221;」と設定することで自動保存を無効化することも可能です。</p>
<ul>
<li>900秒後に1個以上のキーが変更</li>
<li>300秒後に10個以上のキーが変更</li>
<li>60秒後に10000個以上のキーが変更</li>
</ul>
<pre>save 900 1
save 300 10
save 60 10000</pre>
<p>RDBファイルはRedisの起動時に自動的に読み込まれ、前回終了時のデータが復元されます。</p>
<h3>AOF (Append Only File)</h3>
<p>多くの場合は前述のRDBファイルの自動保存でも十分ですが、サーバプロセスの障害や電源断などが発生した場合、直近の数分程度のデータを失う可能性があります。</p>
<p>この問題を回避するのがAOF (Append Only File)となります。</p>
<p>AOFはデータベースのWAL/REDOログに似た書き込みログで、すべての書き込みコマンドが追記で記録されます。AOFはデフォルトでは1秒ごとにfsyncによりディスクに同期される(appendfsync everysec)ので、データを失う可能性のある期間は1秒以内に抑えられます。なお、1回の書き込みごとにfsyncを呼び出すようにする(appendfsync always)こともできますが、非常に遅くなります。</p>
<p>AOFはデフォルトでは無効です。以下の設定で有効にすることができます。また、RDBと同時に使用することもでき、AOFとRDBを両方有効にすることが推奨されています。</p>
<pre>appendonly yes</pre>
<p>AOFファイルはRedisの起動時に自動的に読み込まれます。AOFファイルとRDBファイルの両方が存在する場合はAOFファイルが優先されます。なお、AOFファイルが存在しない状態でAOFを有効にして再起動すると空のAOFファイルを作成するため、<strong>すべてのデータが初期化されてしまう</strong>のでご注意ください。</p>
<h2>バックアップ</h2>
<h3>RDB</h3>
<p>前述の通り、SAVEコマンドもしくはBGSAVEコマンドで現時点のデータのスナップショットをRDBファイルに保存することができます。SAVEコマンドは他のクライアントからのアクセスをすべてブロックしてしまうため、通常はバックグラウンドでデータを保存するBGSAVEコマンドを使用します。BGSAVEコマンドが完了したかどうかはLASTSAVEコマンドで確認できます。RDBファイルはRedisサーバプロセス終了時にも保存されます。</p>
<pre>127.0.0.1:6379&gt; save #保存が完了するまで他の操作はすべてブロックされる
OK
127.0.0.1:6379&gt; lastsave #最終保存時刻(Unix時間)を確認
(integer) 1559267764
127.0.0.1:6379&gt; bgsave #バックグラウンドで保存(すぐに処理が返ってくる)
Background saving started
127.0.0.1:6379&gt; lastsave #最終保存時刻が更新されていることを確認
(integer) 1559267778</pre>
<p>RHEL 7 / CentOS 7のRemiリポジトリのRedisパッケージでは、デフォルトで以下の場所にRDBファイルが保存されます。</p>
<pre>/var/lib/redis/dump.rdb</pre>
<p>このファイルを別の安全な場所に保存します。なお、RDBファイルはアトミックに作成されるので、中途半端な状態のファイルを保存してしまう心配はありません。</p>
<pre># cp /var/lib/redis/dump.rdb /path/to/redis-dump-YYYYMMDD.rdb</pre>
<p>redis-check-rdbコマンドでRDBファイルの正常性を確認することができます。</p>
<pre># redis-check-rdb /tmp/redis-backup-20190531.rdb
[offset 0] Checking RDB file /tmp/redis-backup-20190531.rdb
[offset 26] AUX FIELD redis-ver = '5.0.5'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1559268270'
[offset 67] AUX FIELD used-mem = '1860912'
[offset 83] AUX FIELD aof-preamble = '0'
[offset 85] Selecting DB ID 0
[offset 14677] Checksum OK
[offset 14677] o/ RDB looks OK! o/
[info] 6 keys read
[info] 0 expires
[info] 0 already expired</pre>
<h3>AOF</h3>
<p>RDBのみ有効にした状態からAOFを有効にするには以下のようにします。なお、redis.confのみ修正して再起動すると、前述の通りすべてのデータが初期化されてしまうのでご注意ください。</p>
<pre># redis-cli config set appendonly yes
OK
# vi /etc/redis.conf
appendonly no
↓ 修正
appendonly yes</pre>
<p>デフォルトでは以下の場所にAOFファイルが保存されます。</p>
<pre>/var/lib/redis/appendonly.aof</pre>
<p>AOFは追記型のため、RDBに比べてファイルサイズが大きくなります。そのためバックアップの取得にはRDBが適しています。BGREWRITEAOFコマンドでAOFを再構成し、ファイルサイズを縮小できます。再構成は自動でも行われます。</p>
<pre># ls -l /var/lib/redis/
合計 64152
-rw-r--r--. 1 redis redis 65614804 5月 31 11:32 appendonly.aof
-rw-r--r--. 1 redis redis 21887 5月 31 11:33 dump.rdb
# redis-cli bgrewriteaof
Background append only file rewriting started
# ls -l /var/lib/redis/
合計 48
-rw-r--r--. 1 redis redis 21887 5月 31 11:37 appendonly.aof
-rw-r--r--. 1 redis redis 21887 5月 31 11:33 dump.rdb</pre>
<p>redis-check-aofコマンドでAOFファイルの正常性を確認することができます。</p>
<pre># redis-check-aof /var/lib/redis/appendonly.aof
The AOF appears to start with an RDB preamble.
Checking the RDB preamble to start:
[offset 0] Checking RDB file /var/lib/redis/appendonly.aof
[offset 26] AUX FIELD redis-ver = '5.0.5'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1559269522'
[offset 67] AUX FIELD used-mem = '1859808'
[offset 83] AUX FIELD aof-preamble = '1'
[offset 85] Selecting DB ID 0
[offset 14677] Checksum OK
[offset 14677] o/ RDB looks OK! o/
[info] 6 keys read
[info] 0 expires
[info] 0 already expired
RDB preamble is OK, proceeding with AOF tail...
AOF analyzed: size=65614804, ok_up_to=65614804, diff=0
AOF is valid</pre>
<h2>リストア</h2>
<h3>RDB</h3>
<p>AOFは無効で、RDBのみ使用している場合は以下のようにしてリストアします。</p>
<h4>1. Redisを停止</h4>
<pre># systemctl stop redis</pre>
<h4>2. RDBファイルを書き戻す</h4>
<pre># mv /var/lib/redis/dump.rdb /var/lib/redis/dump.rdb.bak
# cp /path/to/redis-dump-YYYYMMDD.rdb /var/lib/redis/dump.rdb
# chown redis:redis /var/lib/redis/dump.rdb</pre>
<h4>3. Redisを起動</h4>
<pre># systemctl start redis</pre>
<h3>AOF</h3>
<p>AOFファイルからリストアする場合は次のようにします。</p>
<h4>1. Redisを停止</h4>
<pre># systemctl stop redis</pre>
<h4>2. AOFファイルを書き戻す</h4>
<pre># mv /var/lib/redis/dump.rdb /var/lib/redis/dump.rdb.bak (RDBも有効の場合)
# mv /var/lib/redis/appendonly.aof /var/lib/redis/appendonly.aof.bak 
# cp /path/to/redis-appendonly-YYYYMMDD.aof /var/lib/redis/appendonly.aof
# chown redis:redis /var/lib/redis/appendonly.aof</pre>
<h4>3. Redisを起動</h4>
<pre># systemctl start redis</pre>
<h3>RDB (AOF有効時)</h3>
<p>AOFを有効にしている場合にRDBファイルからリストアする場合は注意が必要です。前述の通り、AOFファイルがない場合は起動時に空のAOFファイルを作成し、そちらを参照するため、RDBファイルを配置しても無視されてデータが初期化されてしまいます。そのため、以下の手順のように、AOFを一時的に無効化してRDBファイルからリストアした後AOFを再作成し、AOFの設定を有効化する必要があります。</p>
<h4>1. Redisを停止</h4>
<pre># systemctl stop redis</pre>
<h4>2. RDBファイルを書き戻す</h4>
<pre># mv /var/lib/redis/dump.rdb /var/lib/redis/dump.rdb.bak
# mv /var/lib/redis/appendonly.aof /var/lib/redis/appendonly.aof.bak
# cp /path/to/redis-dump-YYYYMMDD.rdb /var/lib/redis/dump.rdb
# chown redis:redis /var/lib/redis/dump.rdb</pre>
<h4>3. AOFを無効化してRedisを起動</h4>
<pre># vi /etc/redis.conf
appendonly yes → appendonly no

# systemctl start redis</pre>
<h4>4. AOFファイルを書き出す</h4>
<pre># redis-cli bgrewriteaof
Background append only file rewriting started
# redis-cli info | grep aof_rewrite_in_progress
aof_rewrite_in_progress:0
# ls -l /var/lib/redis/
合計 80
-rw-r--r--. 1 redis redis 14677 5月 31 15:21 appendonly.aof
-rw-r--r--. 1 redis redis 21887 5月 31 11:37 appendonly.aof.bak
-rw-r--r--. 1 redis redis 14677 5月 31 15:19 dump.rdb
-rw-r--r--. 1 redis redis 21887 5月 31 14:33 dump.rdb.bak</pre>
<h4>5. AOFを有効化してRedisを再起動</h4>
<pre># systemctl stop redis
# vi /etc/redis.conf
appendonly no → appendonly yes
# systemctl start redis</pre>
<h2>おわりに</h2>
<p>Redisはインメモリデータベースですが、データの永続化が可能となっています。Redisのバックアップ・リストアも非常に簡単で、AOFにより耐障害性の向上も図ることができます。しかしながら、RDBとAOFを両方使用する場合の操作については注意が必要なところがあります。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Redisの紹介</title>
		<link>https://www.sraoss.co.jp/tech-blog/redis/redis-introduction/</link>
		
		<dc:creator><![CDATA[山本 博之 (Hiroyuki Yamamoto)]]></dc:creator>
		<pubDate>Fri, 21 Jun 2019 01:00:38 +0000</pubDate>
				<category><![CDATA[Redis]]></category>
		<category><![CDATA[KVS]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=2674</guid>

					<description><![CDATA[Redisとは Redisはインメモリで動作するKey-Valueストア(KVS)ソフトウェアです。Redisのデータはすべてメモリ内に保存されるため、高速なデータの読み書きが可能です。また、単純なキーと値のペアだけでな ...]]></description>
										<content:encoded><![CDATA[<h3><strong>Redisとは</strong></h3>
<p><a href="https://redis.io/">Redis</a>はインメモリで動作するKey-Valueストア(KVS)ソフトウェアです。Redisのデータはすべてメモリ内に保存されるため、高速なデータの読み書きが可能です。また、単純なキーと値のペアだけでなく様々なデータ構造が利用でき、データの永続化、冗長化、クラスタといった機能を備えており、様々な用途に対応できます。RedisはBSDライセンスの元配布されているオープンソースソフトウェアです。</p>
<p><span id="more-2674"></span></p>
<h2>Redisの特長</h2>
<h3>豊富なデータ構造</h3>
<p>Redisは単純なキーと値のペアだけでなく以下のような様々なデータ型に対応しています。</p>
<ul>
<li><strong>Strings</strong>: テキストまたはバイナリデータ (最大 512MB)</li>
<li><strong>Lists</strong>: 追加された順に並べられた文字列の集合</li>
<li><strong>Sets</strong>: 順序なしの文字列の集合</li>
<li><strong>Sorted Sets</strong>: スコアで順序付けされた文字列の集合 (ランキングなどに使える)</li>
<li><strong>Hashes</strong>: フィールドと値のリストを保存するデータ構造</li>
<li><strong>Bitmaps</strong>: ビット演算を実行できるデータ型</li>
<li><strong>HyperLogLogs</strong>: データセット内の一意の値の数を推定する確率的データ構造</li>
<li><strong>Srtreams</strong>: (Redis 5以降) ストリーム処理のための追記専用の時系列データ構造</li>
</ul>
<h3>データの永続化</h3>
<p>Redisはインメモリデータベースですが、データをディスクに保存しておき、次回起動時にデータを読み込むことで永続化させることができます。</p>
<h3>冗長化</h3>
<p>Redisはマスター・スレーブ型のレプリケーションに対応しています。マスターの死活監視を行い、自動フェイルオーバーを行うことも可能です。複数のマスターから成るCluster構成をとることもできます。</p>
<h2>導入手順</h2>
<h3>前提</h3>
<p>インストール対象の OS として RHEL 7.x / CentOS 7.x を使用します。</p>
<h3>1台構成のインストール</h3>
<p>Redis の最新バージョンのインストールは Remi リポジトリを利用するのが最も簡単です。今回は Remi リポジトリを用いたインストール方法を紹介します。</p>
<h4>1. epel, remiリポジトリのインストール</h4>
<pre># yum install epel-release
# yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm</pre>
<h4>2. Redisパッケージのインストール</h4>
<pre># yum install --enablerepo=epel,remi redis</pre>
<h4>3. Redisの起動</h4>
<pre># systemctl start redis
# systemctl status redis
● redis.service - Redis persistent key-value database
Loaded: loaded (/usr/lib/systemd/system/redis.service; disabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/redis.service.d
└─limit.conf
Active: active (running) since 火 2019-05-21 15:59:30 JST; 5s ago
Main PID: 2391 (redis-server)
CGroup: /system.slice/redis.service
└─2391 /usr/bin/redis-server 127.0.0.1:6379

5月 21 15:59:30 centos7 systemd[1]: Starting Redis persistent key-value database...
5月 21 15:59:30 centos7 systemd[1]: Started Redis persistent key-value database.</pre>
<h4>4. OSの設定</h4>
<p>RHEL 7.x / CentOS 7.x のデフォルトの OS 設定の場合、 Redis 起動時に以下の警告が出る場合があります。</p>
<pre>2391:M 21 May 2019 15:59:30.238 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sy
s/net/core/somaxconn is set to the lower value of 128.</pre>
<p>TCPバックログ(待ち受け可能なTCPセッション数)のOSのデフォルト値は128ですが、Redisのデフォルトでは511が指定されているため、OSのバックログを拡張します。</p>
<pre># sysctl net.core.somaxconn
net.core.somaxconn = 128
# sysctl -w net.core.somaxconn=512
net.core.somaxconn = 512</pre>
<p>OS起動時に有効にするには /etc/sysctl.conf に net.core.somaxconn = 512 を追加します。</p>
<pre>2391:M 21 May 2019 15:59:30.238 # WARNING overcommit_memory is set to 0! Background save may fail under low m
emory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run
the command 'sysctl vm.overcommit_memory=1' for this to take effect.</pre>
<p>空きメモリが少ない状態でのバックグラウンド保存が失敗するのを防ぐため、OSの overcommit_memory を有効にします。OS起動時に有効にするには同様に /etc/sysctl.conf に vm.overcommit_memory = 1 を追加します。</p>
<pre># sysctl vm.overcommit_memory
vm.overcommit_memory = 0
# sysctl -w vm.overcommit_memory=1
vm.overcommit_memory = 1</pre>
<pre>2391:M 21 May 2019 15:59:30.238 # WARNING you have Transparent Huge Pages (THP) support enabled in your kerne
l. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never
&gt; /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain
the setting after a reboot. Redis must be restarted after THP is disabled.</pre>
<p>応答時間やメモリ使用量の問題を防ぐため、OSのTransparent Huge Pages (THP)を無効にします。</p>
<pre># cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
# echo never &gt; /sys/kernel/mm/transparent_hugepage/enabled
# cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]</pre>
<p>OS起動時に有効にするには /etc/sysconfig/grub の GRUB_CMDLINE_LINUX オプションに transparent_hugepage=never を追加します。</p>
<pre># vi /etc/sysconfig/grub
GRUB_CMDLINE_LINUX="rd.lvm.lv=centos/swap vconsole.font=latarcyrheb-sun16 vconsole.keymap=jp106 rd.lvm.lv=centos/root crashkernel=auto  rhgb quiet transparent_hugepage=never"
# grub2-mkconfig -o /boot/grub2/grub.cfg</pre>
<p>上記の修正を反映させるためRedisを再起動します。</p>
<pre># systemctl restart redis</pre>
<h4>5. 自動起動の有効化</h4>
<pre># systemctl enable redis</pre>
<h2>基本的な使い方</h2>
<h3>データの保存・取得</h3>
<p>Redisのコマンドラインツールredis-cliでRedisを直接操作することができます。</p>
<pre>$ redis-cli
127.0.0.1:6379&gt; set hoge 1 #キーに値1を設定
OK
127.0.0.1:6379&gt; get hoge #キーの値を取得
"1"
127.0.0.1:6379&gt; incr hoge #キーの値に1を加算(数値のみ)
(integer) 2
127.0.0.1:6379&gt; get hoge #加算されている
"2"
127.0.0.1:6379&gt; set fuga "aaa" #キーに文字列を設定
OK
127.0.0.1:6379&gt; get fuga
"aaa"
127.0.0.1:6379&gt; keys *      #キー一覧を取得
1) "fuga"
2) "mylist"
3) "myset:__rand_int__"
4) "key:__rand_int__"
5) "hoge"
6) "counter:__rand_int__"</pre>
<p>Redisはキーの種類によって値を取得するコマンドが異なります。</p>
<pre>127.0.0.1:6379&gt; type "myset:__rand_int__"  #キーの種類を取得
hash
127.0.0.1:6379&gt; hgetall "myset:__rand_int__"  #hashの値を取得
1) "element:__rand_int__"
2) "xxx"</pre>
<h3>サーバ情報の取得</h3>
<p>infoコマンドでRedisサーバのリソース使用状況などの様々な情報を取得できます。Redisサーバの状態の監視に使用することができます。</p>
<pre>127.0.0.1:6379&gt; info
# Server
redis_version:5.0.5
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:619d60bfb0a92c36
redis_mode:standalone
...

# Clients
connected_clients:1
client_recent_max_input_buffer:2
client_recent_max_output_buffer:0
blocked_clients:0

# Memory
used_memory:854344
used_memory_human:834.32K
...</pre>
<h3>設定の操作</h3>
<p>config getコマンドで設定情報を取得します。config setコマンドで一時的に設定を変更することもできます。</p>
<pre>127.0.0.1:6379&gt; config get *
1) "dbfilename"
2) "dump.rdb"
...
213) "bind"
214) "127.0.0.1"</pre>
<h2>セキュリティ</h2>
<h3>接続元の制限</h3>
<p>デフォルトの設定ではローカルホストからのみ接続を受け付けます。他ホストからも接続を受け付けたい場合は、 /etc/redis.conf の以下の行に接続を受け付けたいIPアドレスを追加します。</p>
<pre>bind 127.0.0.1
↓
bind 127.0.0.1 192.168.1.100</pre>
<p>なお、bindの行をコメントアウトして無効化し、かつprotected-modeも無効にするとすべてのアドレスから接続を受け付けてしまうためご注意ください。</p>
<h3>認証</h3>
<p>クライアント接続時に認証を行いたい場合は /etc/redis.conf に以下を追加します。</p>
<pre>requirepass &lt;パスワード文字列&gt;</pre>
<pre>127.0.0.1:6379&gt; get hoge
(error) NOAUTH Authentication required.
127.0.0.1:6379&gt; AUTH password
OK
127.0.0.1:6379&gt; get hoge
"2"</pre>
<h2>ベンチマーク</h2>
<p>RedisにはRedisの性能を測定するredis-benchmarkユーティリティが付属しており、簡単にRedisのベンチマークテストを行うことができます。デフォルトでは各種コマンドを10万回実行して実行時間を測定します。</p>
<pre>$ redis-benchmark
====== PING_INLINE ======
  100000 requests completed in 1.50 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.09% &lt;= 1 milliseconds
99.99% &lt;= 2 milliseconds
100.00% &lt;= 2 milliseconds
66711.14 requests per second
...

====== SET ======
  100000 requests completed in 1.45 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.79% &lt;= 1 milliseconds
99.95% &lt;= 2 milliseconds
99.95% &lt;= 16 milliseconds
99.95% &lt;= 18 milliseconds
100.00% &lt;= 18 milliseconds
69156.30 requests per second
...</pre>
<p>-q で結果のみ表示します。</p>
<pre>$ redis-benchmark -q
PING_INLINE: 67024.13 requests per second
PING_BULK: 66357.00 requests per second
SET: 66050.20 requests per second
GET: 65876.16 requests per second
INCR: 69013.11 requests per second
LPUSH: 70028.02 requests per second
RPUSH: 69300.07 requests per second
LPOP: 68917.99 requests per second
RPOP: 68540.09 requests per second
SADD: 68965.52 requests per second
HSET: 70274.07 requests per second
SPOP: 67521.95 requests per second
LPUSH (needed to benchmark LRANGE): 67888.66 requests per second
LRANGE_100 (first 100 elements): 39808.91 requests per second
LRANGE_300 (first 300 elements): 18372.22 requests per second
LRANGE_500 (first 450 elements): 13553.81 requests per second
LRANGE_600 (first 600 elements): 10847.16 requests per second
MSET (10 keys): 66979.23 requests per second</pre>
<h2>おわりに</h2>
<p>Redisは高機能なソフトウェアですが、上記で紹介したように簡単に導入して試すことができます。実際に利用する場合はアプリケーションからライブラリを通してRedisアクセスすることになります。また、業務で使用する場合は冗長化による信頼性の向上も必要となります。</p>
<p>次回はデータの永続化、バックアップとリストア、冗長化など、実際の運用で必要となる機能について解説します。</p>
<div>
<a href="https://www.sraoss.co.jp/prod_serv/support/oss-pro-support/?utm_source=sraoss-techblog&utm_medium=referral&utm_campaign=under-article-oss" rel="noopener" style="color:initial;" target="_blank" class="no-ext"></p>
<div style="background-color:#DAEFF6; padding:20px; border-radius:8px; text-align:center;">
SRA OSSでは、各種OSS のサポートを提供しております。<br />
詳しくは<strong style="color:#2581c4;">弊社ホームページ</strong>をご覧ください。
</div>
<p></a>
</div>

]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
