关于 Redis
由于我没有Redis的经验,所以我会在学习过程中做一些笔记。
特点
Redisはインメモリデータベースとして利用される BSD です。
一般的なデータベースでは、ディスク(ストレージ)にデータを格納し、ディスク上のデータをメモリ上から読み込み、メモリ上のデータをCPUで処理するという流れで動作します。この動作プロセスに対比してインメモリデータベースは、データストレージ用のメインメモリ上にデータを保持し、メモリ上のデータをCPUで処理します。一般的には、RDB よりも Redis は高速であると言われているようです。
RDBのバッファプールのようにキャッシュしたデータに参照データが無いものはディスクから読み取りする訳ではない為、メモリの容量内に全てのデータを収める必要性があります。
NoSQL データベースであり KVS です。
NoSQL (非リレーショナル) データベースは RDB(リレーショナルデータベース)の対義で、RDB のように表形式の関係モデルではないデータベースを NoSQL として総称しています。また、KVS(Key-Value-Store) は、キーに対して値(value)を書き込み、キーを指定することで値を読み出す事が出来るデータベース管理ソフトウェアです。なので、NoSQL の一種である KVS を採用しています。が適語かと思います。
KVS はキー同士に関連性がない分、分散化(複数台のサーバを使用)するコストが低くなる特性があります。なお、耐障害性としてのレプリケーションがありますが、分散化とはデータの配置先を表現しており、aサーバとbサーバには別々のデータが格納されている事を示します。後述に挙げる Redis cluster、Redis Replication がこれに該当します。
client/serverモデルを使用します。
複数のクライアントからのアクセスが可能です。client からTCP/IP (defalut port:6379) のリクエストを送り、サーバー側の Redis が結果をレスポンスとして client(アプリケーション側)に返します。
永続的にデータを保持する機能があります。
KVS には、データを保持する観点から揮発性KVSと永続性KVSに分かれます。
Redis は、メインメモリのデータが揮発性なので、時間が経つとデータが消えてしまう 揮発性KVS に分類されるようですが、Redis はメモリ上のデータをストレージに格納してデータを永続的に保持する機能があります。
构成和规格
使用内存
Redis可以在内存中进行处理,因此可以设置物理内存的上限值,并设置超过上限值时的处理行为。
数据结构
Redis がサポートするデータ構造は以下です。
データ構造とはデータを効果的に使用するために、一定の方式に沿ってデータを格納する形式を表現しています。
单线程
由于Redis是单线程的,所以无法进行像其他RDB那样的并行处理。它每次只能执行一个线程的处理。
数据库 (databases)
在一个Redis服务器上可以创建多个数据库。这些数据库内部存储以键值对形式的数据。
Redis服务器的多台配置
Redis Cluster
シャーディングにより、データを複数のRedisサーバに自動的に分散する事が出来ます。
また、フェールオーバー機能として、自動的にスレーブノードがマスターノードに昇格する機能があります。
なお、redis clusterはスロットと呼ばれる番号でデータを格納し、スロットの番号に沿っていずれかのノードにデータが格納されます。
負荷分散や可用性に特化した構成は、 Cluster構成を選びますが、ノードダウン時の一時的なデータ参照不可が可能性としてあります。
Redis Replication
Redis のレプリケーションはマスターレプリカの構成で非同期レプリケーションですが、読み取り側は、マスターと定期的に受信したデータの量を非同期的に確認します。ただし、Redis Replication は自動のフェイルオーバー機能を保持していないため、手動での切り替えになります。
Redis がダウンしても急いで復旧するシステムではない問題ない場合には Replication のシンプル構成を選びます。
Redis Sentinel
サーバの死活監視や通知機能提供されており、監視対象のサーバが落ちた場合に自動フェイルオーバーなどが行うことができます。
監視対象のマスターに対して複数のSentinelプロセスを起動させておき、マスターの情報を共有しあいます。マスターがダウンした際に、投票方式で過半数以上のSentinelプロセスがダウンしたと判断すると自動的にフェイルオーバーします。
フェールオーバーの機能と、フェールオーバーの復旧時間が許されるのであれば、Sentinel 構成などを選びます。
数据备份
可以通过命令和设置参数,在指定的时间间隔内将Redis服务器的所有数据保存为.rdb文件格式的快照(点对点)。
另一种方法是通过启用AOF(追加写入文件)设置,将接收到的所有写入操作记录到文件中,在服务器启动时进行恢复,重新构建原始数据集。
验证
根据上述内容,我会在AWS的EC2(ubuntu)上安装Redis服务器并进行尝试。
sudo apt install redis-server
redis-server --version
> Redis server v=5.0.7 sha=00000000:0 malloc=jemalloc-5.2.1 bits=64 build=636cde3b5c7a3923
Redis的设置由/etc/redis/redis.conf文件进行管理。
为了节省篇幅,只确认已启用的设置。
cat redis.conf | grep -v "#"
bind 127.0.0.1 ::1
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile /var/run/redis/redis-server.pid
loglevel notice
logfile /var/log/redis/redis-server.log
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
replica-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
我只需要确认一下重要的设置。
hash-max-ziplist-valueフィールド(子キー)の最大サイズ(byte)client-output-buffer-limitクライアントとの接続を切断する容量しきい値を示します。nomal は通常のクライアントを示し、0は無効化。値を入れる場合は、mb(メガバイト) 形式で入れるreplicaofこれはデフォルト無効化となっている設定ですが、replicaof はredisをreplicaとして設定する設定値
接下来,我将在服务器上尝试输入命令。
$ redis-cli
首先,我们需要确认数据库存在16个。
127.0.0.1:6379> CONFIG GET databases
1) "databases"
2) "16"
接下来,将显示数据库中的数据量。
在这种情况下,它表示db0中存在一个key。
127.0.0.1:6379> INFO keyspace
# Keyspace
db0:keys=1,expires=0,avg_ttl=0
当显示数据库0 的键时,显示了“test”。
127.0.0.1:6379> select 0
OK
127.0.0.1:6379> keys *
1) "test"
用mset方法将Strings的key:value保存起来。
key:test test2 test3,value分别返回1。
mset test 1
mset test2 1
mset test3 1
mget test test2 test3
127.0.0.1:6379> mget test test2 test3
1) "1"
2) "1"
3) "1"
然后使用 lpush 来保存 key:value 的 list。
llen 返回列表的长度,lpop 提取列表的第一个值。
127.0.0.1:6379> lpush test4 1 2 3
(integer) 3
127.0.0.1:6379> llen test4
(integer) 3
127.0.0.1:6379> lpop test4
"3"
127.0.0.1:6379> llen test4
(integer) 2
接下来,使用sadd命令将sets的键值对保存。
smembers会返回value的值,scard会获取数量。
127.0.0.1:6379> sadd test6 1 2 3
(integer) 3
127.0.0.1:6379> smembers test6
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> scard test6
(integer) 3
最后,使用hset将Hashes的父键:子键:值保存。利用hgetall获取所有子键(字段)和值。
hset test7 a 1
hset test7 b 1
hgetall test7
127.0.0.1:6379> hgetall test7
1) "a"
2) "1"
3) "b"
4) "1"
接下来,我会查看备份还原列表。
检查当前的键数,然后在后台通过 bgsave 命令执行。执行完毕后,会在 RDB 文件路径中生成 dump.rdb 文件,将其用作备份文件。停止 redis 进程并将备份文件重命名并移动到其他位置。然后启动 redis,删除键并重新启动以确认恢复是否成功。
127.0.0.1:6379> dbsize
(integer) 7
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379> lastsave
(integer) 1633911531
sudo service redis stop
sudo mv /var/lib/redis/dump.rdb /var/lib/redis/dump.rdb.bak
sudo cp /var/log/dump.rdb /var/lib/redis/dump.rdb
chown redis:redis /var/lib/redis/dump.rdb
sudo service redis start
127.0.0.1:6379> del test4 test5
(integer) 2
sudo service redis stop
sudo service redis start
127.0.0.1:6379> dbsize
(integer) 7
最后是来自客户端的处理。
使用Windows执行处理并将其传输到Redis。
通过pip安装Redis模块。
pip install redis
以下是 test.py 的内容。
import redis
r = redis.Redis(host='接続IP', port=6379, db=0)
r.set('test10', '1')
1 = r.get('1')
print(1.decode())
在Redis服务器端,开放安全组的6379端口。
将客户端的IP添加到/etc/redis.conf的protected-mode和bind选项中。
protected-mode no
bind 127.0.0.1 <client-IP>
通过这个,连接就完成了。