【Redis】【Python3】Redis-ServerのインストールとPythonで行うpublish/subscribe

# 0. はじめに
Redisとは簡単にいうとNoSQLのデータベースサーバである。
簡易なメッセージ機能であるpublish/subscribe(Androidで例えるならIntent的なもの)を有している。
![概略.png](https://qiita-image-store.s3.amazonaws.com/0/235452/9534f55a-5653-ffcb-350b-ecb28dba5953.png)
Redis-Serverのインストールとpublish/subscribeについて記載する。

# 1. インストール
## インストール
以下コマンドでインストールできる。

```
$ sudo apt-get update
$ sudo apt-get install redis-server
```

## 動作確認
サーバーのバージョン確認

```
$ redis-server -v
```

クライアントのバージョン確認

```
$ redis-cli -v
```

# 2. publish/subscribe
## Redis-pyのインストール
以下にPythonでRedisを扱うサンプルを載せているが、それにはRedis-pyをインストールする必要がある。

```
$ pip3 install redis
```

## publish
publishは指定したチャンネルにメッセージを投げる操作。
リファレンス→https://redis.io/commands/publish

```bash
$ redis-cli
> publish channel message
```
当然、チャンネルとメッセージは自由に設定できる。
ここで送信したメッセージはDBに保存されない。
以下はこれをPythonで行うサンプルである。

```python3:publish_test.py
import redis
import time

host = 'localhost'
port = 6379

def run_publish(loopCount):
    # redisに接続
    connect = redis.StrictRedis(host=host, port=port)
    
    for i in range(loopCount):
        # publish
        connect.publish('publish', 'xxxxx')
        time.sleep(1)

if __name__ == '__main__':
    run_publish(10)
```

publish()関数の第１引数で送信するチャンネルを指定し、第２引数でメッセージを指定する。
やっていることは以下のコマンドを10回送信しているだけ。

```bash
> publish publish xxxxx
```

## subscribe
subscribeは指定したチャンネルに投げられたメッセージを取得する操作。
リファレンス→https://redis.io/commands/subscribe

```bash
$ redis-cli
> subscribe channel
```

監視を開始する前に送信されたメッセージは取得できない。
チャンネルの後に他のチャンネルを指定すれば同時に複数のチャンネルを監視できる。
以下はchannel01とchannel02という二つのチャンネルを監視する例。

```bash
$ redis-cli
> subscribe channel01 channel02
```

試しに監視しているチャンネルにpublishでメッセージを送信すれば受信できることが確認できるだろう。
（下から３行が受信したメッセージ）

```bash
$ redis-cli
> subscribe channel01
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel01"
3) (integer) 1
1) "message"
2) "channel01"
3) "test_message"
```

そして以下がPythonで行う例。

```python3:subscribe_test.py
import redis

host = 'localhost'
port = 6379

def run_subscribe():
    # redisに接続
    connect = redis.StrictRedis(host=host, port=port)
    # Pubsubオブジェクト生成
    pubsub = connect.pubsub()
    # subscribe開始
    pubsub.subscribe(['subscribe'])
    for item in pubsub.listen():
        print(item)
        # 値が"end"ならばsubscribeを終了させる
        # channel、dataはbyte列な場合があるので必要に応じてデコードする
        data = item.get('data')
        if isinstance(data, bytes):
            data = data.decode('utf-8')
        if data == 'end':
            # subscribe終了
            pubsub.unsubscribe()
            break

if __name__ == '__main__':
    run_subscribe()
```

subscribe()関数の引数で監視するチャンネルを指定する。
このサンプルのポイントは受信したメッセージをデコードしていること。
これをしないとメッセージを正しく処理できず、期待した動作をしなくなる。
（サンプルを例に出すとスクリプトが終了しない）
subscribeを終える際はunsubscribe()関数を呼び、監視を終了させるのを忘れずに。

## psubscribe
監視するチャンネルが多いとチャンネル指定が面倒になる。
監視対象のチャンネルをパターン指定できるコマンドも用意されている。
リファレンス→https://redis.io/commands/psubscribe

```bash
$ redis-cli
> psubscribe pattern
```

パターン指定できるので、送信されているメッセージを全て監視することも可能。
（余計なメッセージが送信されていないか等のテストに便利）

```bash
$ redis-cli
> psubscribe *
```

もちろん、Pythonで使用することも可能。
（余計なチャンネルを拾い、不具合の原因になりかねないので個人的にはオススメしない）

```python3:psubscribe_test.py
import redis

host = 'localhost'
port = 6379

def run_psubscribe():
    # redisに接続
    connect = redis.StrictRedis(host=host, port=port)
    # Pubsubオブジェクト生成
    pubsub = connect.pubsub()
    # psubscribe開始
    pubsub.psubscribe(['*'])
    for item in pubsub.listen():
        print(item)
        # 値が"end"ならばpsubscribeを終了させる
        # channel、dataはbyte列な場合があるので必要に応じてデコードする
        data = item.get('data')
        if isinstance(data, bytes):
            data = data.decode('utf-8')
        if data == 'end':
            # psubscribe終了
            pubsub.punsubscribe()
            break

if __name__ == '__main__':
    run_psubscribe()
```

# 3. 終わりに
publish/subscribeは簡単な内容の通信を実装するのに、非常に便利に思えます。
（簡単に実装でき、通信内容も簡単に覗けるため）

# 98. 参考
PythonでRedisを扱う(redis-pyの基本) - http://www.denzow.me/entry/2017/10/07/233233
[Tips] Python から Redis を使う (8) ~ PUB/SUB ~ - http://mocobeta-backup.tumblr.com/post/81758811694/tips-python-%E3%81%8B%E3%82%89-redis-%E3%82%92%E4%BD%BF%E3%81%86-8-pubsub
redis-py - https://github.com/andymccurdy/redis-py
Command reference – Redis - https://redis.io/commands

# 99. 更新履歴
|日付|変更内容|
|:--|:--|
|2018/02/08|投稿|