macのローカル環境でRedisを触ってみる

最近は実務でAWSのElastiCache for redisというサービスについて調べる機会がありました。実務ではAWSのEC2（仮想サーバ）上で動作するKVSサービスを扱いましたが、今回はmacのローカル環境でKVSの操作方法を学ぶべく、redisの概要をまとめようと思います。本記事では各用語解説からredisのインストール、KVSの操作を行っていきます。

MacOS：Version 11.1
redis-cli：Version 6.2.6

## 1.KVSとは？redisとは？

KVSはデータの保存方式の一種で「Key Value Store」の略です。キー(Key)となる値に保存したい値(Value)が結びついている形でデータを格納しています(Store)。

データの保存・管理方法として、表形式で値を格納するリレーショナルデータベース(RDB)を最初に思い浮かべる方が多いかもしれません。

RDBでは構造化された複雑なデータを、SQL文を用いて操作します。場合によってはいくつかの表形式データが関連性を持っているなど複雑な構造になっています。一方KVSでは個別で多様なデータを、キーの値を用いて操作します。KVSはRDBのように構造的に整理されていないため複雑な処理を行うには不向きですが、データの構造化が不要なため時間的・費用的コストが抑えられる、高速なデータ読み書きが可能であるといったメリットがあります。
ちなみにKVSはSQLを用いてデータ操作をするわけではないため、NoSQLと呼ばれる、RDBと対になるデータ管理方法の一つとして認識されています。

対比表にまとめてみると、以下のようになります。

||**RDB**|**KVS**|
|:--|:--|:--|
|**データの様子**|構造化され互いに関連性がある|個別で多様なデータが存在している|
|**操作方法**|SQL|キーを指定して操作|
|**長所**|複雑な処理ができる、データ保全性が高い|時間的・費用的コストが低い、読み書きが高速|
|**短所**|構造化が手間、データ読み書きに時間がかかる|複雑な処理に不向き、データが消えるかもしれない|
|**AWSの代表的サービス**|RDS|ElastiCache|


○RDBとKVSのイメージ（引用元：[もう1つの、DBのかたち、分散Key-Valueストアとは](https://atmarkit.itmedia.co.jp/ait/articles/0907/02/news101.html)）
![スクリーンショット 2021-10-28 16.51.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1676583/7ceb2418-7d7c-f4f7-e30b-beec11d7de52.png)

ElastiCacheはAWSのキャッシュサービスの一つです。キャッシュとは一度利用したデータに高速でアクセスすることを指します。AWSにはDynamoDBやRDSなどのDBサービスがありますが、そのようなデータ保管方法よりも高速にアクセスしたい場合や、中のデータが万が一消えてしまっても問題がない場合にElastiCacheが選ばれます。

（ElastiCacheのロゴ　引用元：[ElastiCacheは良いサービス！！特徴や使い方をおさらいしましょ！](https://dev.classmethod.jp/articles/elasticache-is-very-good-lets-review/)）
![スクリーンショット 2021-10-28 16.51.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1676583/a65e5e79-133e-85c4-6dba-d4deeaf2b817.png)

ElastiCacheに保管されているデータをマネージするエンジンとしてRedisとMemchachedという二つのものがサポートされています。複雑な作業を行いたい場合は一般的にRedisを選択することが多いようです。

私は実務でEC2上に構築されたElastiCacheノードを扱っているのですが、今回はRedisを用いてローカルにキャッシュメモリ環境を構築し、KVSのデータを扱っていきます。

## 2.Redisのインストールと起動

macには、homebrewを使ってRedisをインストールしました。brewコマンドが使えない場合はまず以下のコマンドでhomebrewをインストールしてください。後半に「Installation successful!」の文字が見えていれば完了です。

```
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

きちんとhomebrewがインストールされているか、以下のコマンドでバージョンを確認してみます。きちんとバージョンが表示されていたらうまくインストールできています。

```
$ brew -v
```

><補足>
M1チップが搭載されているmacではうまくhomebrewがインストールできないことがあるようです。その場合はfinderでTerminalを検索し、「情報を見る」から「Rossetaを使用して開く」にチェックを入れます。そのままでは設定が適用されないことがあるようなので、mac本体を再起動しましょう。改めてhomebrewインストールのコマンドを叩いてみてください（[参考記事](https://qiita.com/___fff_/items/17655df4e80ebadd8fc3)）。

それではredisをインストールしていきます。まずは念のためHomebrewを更新し、最新の状態にしておきます。

```
$ brew update
```

以下のコマンドでredisをインストールしましょう。

```
$ brew install redis
```

これで準備が整いました。以下のコマンドでローカル環境のredisを起動しましょう。うまく立ち上がれば続けてプロンプトが出てくるはずです。

```
$ redis-cli
127.0.0.1:6379> 
```

このコマンドを実行すると自動でredisサーバが立ち上がりKVS操作をできる状態になるはずですが、「not connected」というプロンプトが出てきた場合はうまくサーバが立ち上がっていません。一度「quit」と入力してredis操作から抜けて、以下に示すコマンドを試してください。

```
$ redis-server
（サーバを直接立ち上げるコマンド。Terminalがそのまま接続待機中になるので別画面で「redis-cli」コマンドを試してください。)
$ redis-cli ping 
(redisサーバが立ち上がっているか確認するコマンド。うまく立ち上がっていれば「pong」とレスポンスが返ってくる)
```

先述した「127.0.0.1:6379>」 のプロンプトが出るようになったら、早速KVSでデータを扱ってみましょう。
ちなみにこのプロンプトの127.0.0.1は自身のローカル環境を指しており、6379はRedisのデフォルトのポートを意味しています。

## 3.データの書き込み・読み込みをしてみる
KVSの形で保存されているデータ構造には、大きく分けて以下の３種類があり、それぞれの構造で使用するコマンドが変わります。
・キーと値が１対１で対応する文字列型
・ひとつのキーに対して複数の値があるリスト型・セット型
・キーに対してフィールドが設定されており、それに対する値が存在するハッシュ型
それぞれのデータ構造、データの書き込み・読み込みの方法について説明します

###キーと値が１対１で対応する文字列型
例えば、ある会員制サイトにアカウントを持つユーザのIDを下に、その会員が専用アプリをダウンロードしてあるかどうかを判定する業務システムを想定します。ユーザがアプリをダウンロードした際、ユーザIDをキーとして適当な値（”１”など）をKVSに登録します。KVSにアクセスし、ユーザIDがキーとして存在していた場合は、そのユーザが専用アプリをダウンロードしていると判断します。このような例で用いたKVSが文字列型となります。

```
10001 “1”
10002 “1”
10003 “1”
```

この文字列型で使える代表的なコマンドは以下です。

|**コマンド**|**処理**|
|:--|:--|
|set <キー> <値>|ひとつのキーと値のペアをセットする。キーと値は半角スペースで区切る|
|mset <キー> <値> <キー> <値>...|複数のキーと値のペアをセットする|
|get <キー>|指定したキーの値を取り出す、もしくはキーが存在しているか確認する|
|mget <キー> <キー>...|複数のキーを指定し値を取り出す、もしくはキーが存在しているか確認する|
|keys *|どのようなキーが登録されているかを一覧で表示する|

以下に使用例を示します

```
127.0.0.1:6379> set 10001 1
OK
127.0.0.1:6379> mset 10002 1 10003 1
OK
127.0.0.1:6379> keys *
1) "10003"
2) "10001"
3) "10002"
127.0.0.1:6379> get 10001
"1"
127.0.0.1:6379> mget 10002 10003
1) "1"
2) "1"
127.0.0.1:6379> get 10004
(nil)
```

###ひとつのキーに対して複数の値があるリスト型・セット型
いずれもひとつのキーが複数の値を持つ構造になっていますが、リスト型では値の順番が決まっており、セット型は順不同です。

セット型KVSを考えるにあたって、この会員サイトをどこで知ったかというユーザアンケートの複数回答可の項目に対し、ユーザがなんと回答したかを集計するシステムを例に取り上げます。複数の値を持つという点以外は、基本的な考え方は文字列型と同じです。

この型では以下のようなコマンドが使えます。

|**コマンド**|**処理**|
|:--|:--|
|sadd <キー> <値> <値> <値>...|キーに対して値をセットする|
|smembers <キー>|キーの持つ値を表示する|

```
127.0.0.1:6379> sadd 10001 web flyer ad
(integer) 3
127.0.0.1:6379> smembers 10001
1) "ad"
2) "web"
3) "flyer"
127.0.0.1:6379> sadd 10002 web ad
(integer) 2
127.0.0.1:6379> smembers 10002
1) "ad"
2) "web"
```

値の順番が決まっているリスト型では以下のコマンドが使用できます。各値にインデックスがついているため、値取得の範囲を絞っての操作が可能です。インデックスは0から始まります。

|**コマンド**|**処理**|
|:--|:--|
|rpush <キー> <値>|リストの末尾に値を挿入する|
|lpush <キー> <値>|リストの先頭に値を挿入する|
|lrange <キー> <インデックス始点> <インデックス終点>|指定した範囲のキーの値を取り出す、もしくはキーが存在しているか確認する|

```
127.0.0.1:6379> rpush 10003 zero
(integer) 1
127.0.0.1:6379> rpush 10003 one
(integer) 2
127.0.0.1:6379> lpush 10003 two
(integer) 3
127.0.0.1:6379> lrange 10003 0 2
1) "two"
2) "zero"
3) "one"
```

###キーに対してフィールドが設定されており、それに対する値が存在するハッシュ型

今までの型よりも構造が一段深くなるイメージで、各値に対してフィールドを設定します。ユーザIDに対して住んでいる地域、趣味など項目ごとに値をセットするケースが想定できますね。使われるコマンドは以下です。

|**コマンド**|**処理**|
|:--|:--|
|hset <キー> <フィールド名> <値>|キーに結びつく値とそのフィールドをセットする|
|hget <キー> <フィールド名>|キーのフィールドに結びつく値を表示する|
|hkeys <キー>|キーに結びついているフィールドを表示する|
|hvals <キー>|フィールドは無視して、キーに対する値だけを表示する|

```
127.0.0.1:6379> hset 10004 region kanto hobby tennis
(integer) 2
127.0.0.1:6379> hset 10005 region shikoku hobby baseball
(integer) 2
127.0.0.1:6379> hget 10004 hobby
"tennis"
127.0.0.1:6379> hkeys 10004
1) "region"
2) "hobby"
127.0.0.1:6379> hvals 10005
1) "shikoku"
2) "baseball"
```

###その他
|**コマンド**|**処理**|
|:--|:--|
|quit|redis接続を終了する|
|dbsize|存在するキーの数をカウントする|

この他にもたくさんコマンドがありますし、値の削除コマンドなども型によって微妙に異なってきます。[こちらの公式サイト](https://redis.io/commands)でコマンドの検索ができます。[こちらの記事](https://blog.sojiro.me/blog/2014/07/27/rediss-data-type-and-usage/)ではデータ型ごとにコマンドがまとめられていて、大変参考になりました。

## 4.おわりに

以上、macのローカル環境でRedisを使う環境を構築＆実際に値を操作する方法をご紹介しました。ローカル環境だけでRedisを使う場合のユースケースは想定しづらいですが、実務ではEC2サーバ上のKVSを扱うことで、高速なデータのやり取りが可能になります。今後もより深いところまで学習を進めていければと思います。



参考記事：
[Redisの起動と停止](https://qiita.com/horiko/items/bc812a03c9e0566d6338)
[Homebrewの基本とインストール方法・使い方](https://dot-blog.jp/news/homebrew-how-to-install/)
[MacOSのローカル環境にRedisをインストールする方法](https://dot-blog.jp/news/redis-mac-how-to-install/)
[【M1】MacにHomebrwがインストールできない「zsh: command not found: brew」](https://qiita.com/___fff_/items/17655df4e80ebadd8fc3)
[KVSとは](https://e-words.jp/w/KVS.html)
[NoSQLとは？リレーショナルデータベース（RDB）との違いを徹底比較](https://blog.codecamp.jp/what-is-nosql)
[Amazon ElastiCacheとは？RedisとMemcachedの違いとは](https://www.sunnycloud.jp/column/20210428-01/)
[ElastiCacheは良いサービス！！特徴や使い方をおさらいしましょ！](https://dev.classmethod.jp/articles/elasticache-is-very-good-lets-review/)
[Redisについて各データ型と想定用途をまとめてみた](https://marunouchi-tech.i-studio.co.jp/3366/)
[Redisに用意されたデータ型とその扱い](https://blog.sojiro.me/blog/2014/07/27/rediss-data-type-and-usage/)
[Redis Commands](https://redis.io/commands)