陈中正的网络日志

Redis笔记

1、安装与启动

如何安装

brew install redis

配置Redis-Server

#设置成Daemon
daemonize yes

#绑定非localhost网卡,
#确保server和sentinel在同一台机器时的注册ip不是127
bind 192.168.20.100

#这样可以通过密码访问(如果没有密码只能限制本地访问)
requirepass abc123

启动服务端

redis-server /usr/local/etc/redis.con

启动客户端

redis-cli
redis-cli -h host -p port -a password

#检查redis是否启动
>PING
PONG

相关脚本

ps -ef | grep redis-sentinel | grep -v grep | awk '{pring $2}' | xargs kill

cd redis-4.0.1
src/redis-sentinel sentinel.conf
cd ..

cd redis-4.0.1-2
src/redis-sentinel sentinel.conf
cd ..

cd redis-4.0.1-3
src/redis-sentinel sentinel.conf
cd ..

2、配置

2.1、查看配置

  • 语法
CONFIG GET CONFIG_SETTING_NAME
  • 实例
#查看loglevel
CONFIG GET loglevel
#查看所有
CONFIG GET *
  • 常用命令
说明 命令
获取所有的配置信息 CONFIG GET *
获取loglevel的配置信息 CONFIG GET loglevel

2.2、修改配置

  • 语法
CONFIG SET CONFIG_SETTING_NAME NEW_CONFIG_VALUE
  • 实例
#设置loglevel
CONFIG SET loglevel "notice"

2.3、常用配置项

redis.conf 配置项说明如下:

  • 设置是否守护进程
daemonize no
  • 监听端口
port 6379
  • 绑定IP
bind 127.0.0.1

注意:如果没有指定,则监听所有网卡的IP

  • 客户端关闭超时时间

客户端闲置多长时间后关闭连接

timeout 300

如果指定为0,表示关闭该功能

  • 日志记录方式 默认为标准输出,如果配置Redis为守护进程方式运行 且这里配置为标准输出,则日志将会发送给/dev/null
logfile stdout
  • 指定持久化策略

指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合

save <seconds> <changes>

Redis默认配置文件中提供了三个条件:

save 900 1
save 300 10
save 60 10000

分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。

  • 本地数据库文件名
dbfilename dump.rdb

默认值为dump.rdb

  • 本地数据库存放目录
dir ./
  • Redis最大内存限制
maxmemory <bytes>

Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区

  • 是否在每次更新操作后进行日志记录

指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no

appendonly no
  • 更新日志文件名

默认为appendonly.aof

appendfilename appendonly.aof
  • 更新日志条件
appendfsync everysec

共有3个可选值:
no:表示等操作系统进行数据缓存同步到磁盘(快)
always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
everysec:表示每秒同步一次(折衷,默认值)

  • 指定包含其它的配置文件
include /path/to/local.conf

可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件

3、数据类型

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

String(字符串)

string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
string类型是Redis最基本的数据类型,一个键最大能存储512MB。

>SET name "runoob"
>GET name

Hash(哈希)

Redis hash 是一个键名对集合。
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

#设置一个Map,键为user:1,并插入3个kv
>HMSET user:1 username runoob password runoob points 200
#获取一个Map所有值
>HGETALL user:1

List(列表)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

#左侧插入三个值
>lpush runoob redis
>lpush runoob mongodb
>lpush runoob rabitmq
#列出0-10个元素
>lrange runoob 0 10

Set(集合)

Redis的Set是string类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

Zset (有序集合)

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。
redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。

4、Redis命令1

键(Key)

  • 语法

    COMMAND KEY_NAME

  • 实例
    ```

    SET runoobkey redis
    DEL runoobkey
    ```

  • 常用命令

命令 说明
DEL key 该命令用于在 key 存在时删除 key。
DUMP key 序列化给定 key ,并返回被序列化的值。
EXISTS key 检查给定 key 是否存在。
EXPIRE key seconds 为给定 key 设置过期时间。
KEYS pattern 查找所有符合给定模式( pattern)的 key 。 (查看所有key: KEYS *)
RENAME key newkey 修改 key 的名称
TYPE key 返回 key 所储存的值的类型。

字符串(String)

  • 语法 redis 127.0.0.1:6379> COMMAND KEY_NAME
  • 常用命令
序号 命令及描述
1 [SET key value]  设置指定 key 的值
2 [GET key] 获取指定 key 的值。
3 [GETRANGE key start end]  返回 key 中字符串值的子字符
4 [GETSET key value] 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。

哈希(Hash)

列表(List)

集合(Set)

有序集合(Sorted Set)

发布订阅

发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

  • 实例

订阅频道redisChat:

SUBSCRIBE redisChat

向某个频道发布消息

PUBLISH redisChat "Redis is a great caching technique"
  • 常用命令
序号 命令 描述
1 PSUBSCRIBE pattern [pattern ...] 订阅一个或多个符合给定模式的频道。
2 PUBSUB subcommand [argument [argument ...]] 查看订阅与发布系统状态。
3 PUBLISH channel message 将信息发送到指定的频道。
4 PUNSUBSCRIBE [pattern [pattern ...]] 退订所有给定模式的频道。
5 SUBSCRIBE channel [channel ...] 订阅给定的一个或多个频道的信息。
6 UNSUBSCRIBE [channel [channel ...]] 指退订给定的频道。

5、理论

5.1、Redis持久化

http://redisdoc.com/topic/persistence.html

6、高级特性

6.1、主从分离2

  • 所有redis配置 每个redis实例的redis.conf文件配置以下内容
# 端口配置
port 6379

# 修改pidfile
pidfile /var/run/redis_6379.pid
  • Slave Redis配置 Slave实例除了以上配置之外还要配置以下内容
# 设置master
slaveof 127.0.0.1 6379
# 设置master的密码
masterauth <master-password>
  • 启动所有server实例
> src/redis-server redis.conf
  • 确认 主从角色
> src/redis-cli -p 6379 -a abc123
> info

...
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=322,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=322,lag=0

6.2、读写分离3

  • 配置文件 在master的配置文件中配置:
slave-read-only yes

6.3、Sentinel相关

6.3.1、Sentinel有什么用

  • Monitoring. Sentinel constantly checks if your master and slave instances are working as expected.
  • Notification. Sentinel can notify the system administrator, another computer programs, via an API, that something is wrong with one of the monitored Redis instances.
  • Automatic failover. If a master is not working as expected, Sentinel can start a failover process where a slave is promoted to master, the other additional slaves are reconfigured to use the new master, and the applications using the Redis server informed about the new address to use when connecting.
  • Configuration provider. Sentinel acts as a source of authority for clients service discovery: clients connect to Sentinels in order to ask for the address of the current Redis master responsible for a given service. If a failover occurs, Sentinels will report the new address.

6.3.2、Sentinel配置

  • 配置文件配置4

每个sentinel.conf 中添加以下配置:

# 确保从非localhost网卡可以访问
#protected-mode no

# 绑定非localhost网卡
# 确保server和sentinel在同一台机器时的注册ip不是127
bind 192.168.20.100

# 端口
port 26379

# redis集群的master
# 不需要配置slave,因为可以自动获取
# sentinel monitor <master-group-name> <ip> <port> <quorum>
# The quorum is the number of Sentinels that need to agree about the fact the master is not reachable, in order for really mark the slave as failing, and eventually start a fail over procedure if possible.
# 注意:
# 绑定非localhost网卡
# 确保server和sentinel在同一台机器时的注册ip不是127
sentinel monitor mymaster 192.168.20.100 6379 2

# 以及所有 mymaster 出现的地方添加每组redis配置

# 设置成守护进程
daemonize yes

6.3.3、Sentinel相关命令

  • 启动多个sentinel实例
> src/redis-sentinel sentinel.conf
  • 查看sentinel状态
src/redis-cli -p 26379
127.0.0.1:26379> SENTINEL get-master-addr-by-name mymaster

6.4、分片

6.4.1、如何选择分片方案5

RedisSharding

RedisSharding.gliffy

6.4.2、Redis Sentinel Sharding 配置

参考[6.3.2、Sentinel配置][6.3.2、Sentinel配置],在sentinel配置中添加多个sentinel monitor

7、算法

7.1、一致性哈希

1、定义6

一致哈希 是一种特殊的哈希算法。在使用一致哈希算法后,哈希表槽位数(大小)的改变平均只需要对K/n个关键字重新映射,其中K是关键字的数量,n是槽位数量。然而在传统的哈希表中,添加或删除一个槽位的几乎需要对所有关键字进行重新映射。

2、评判标准7

  • 平衡性(Balance):平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这一条件。
  • 单调性(Monotonicity):单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。
  • 分散性(Spread):在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。
  • 负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同 的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。

3、如何实现7

3.1、如何实现单调性?

在分布式集群中,对机器的添加删除,或者机器故障后自动脱离集群这些操作是分布式集群管理最基本的功能。如果采用常用的hash(object)%N算法,那么在有机器添加或者删除后,很多原有的数据就无法找到了,这样严重的违反了单调性原则。接下来主要讲解一下一致性哈希算法是如何设计的:

  • 环形Hash空间
    按照常用的hash算法来将对应的key哈希到一个具有2^32次方个桶的空间中,即0~(2^32)-1的数字空间中。现在我们可以将这些数字头尾相连,想象成一个闭合的环形。如下图

  • 把数据通过一定的hash算法处理后映射到环上
    现在我们将object1、object2、object3、object4四个对象通过特定的Hash函数计算出对应的key值,然后散列到Hash环上。如下图:
    Hash(object1) = key1;
    Hash(object2) = key2;
    Hash(object3) = key3;
    Hash(object4) = key4;

  • 将机器通过hash算法映射到环上
    在采用一致性哈希算法的分布式集群中将新的机器加入,其原理是通过使用与对象存储一样的Hash算法将机器也映射到环中(一般情况下对机器的hash计算是采用机器的IP或者机器唯一的别名作为输入值),然后以顺时针的方向计算,将所有对象存储到离自己最近的机器中。
    假设现在有NODE1,NODE2,NODE3三台机器,通过Hash算法得到对应的KEY值,映射到环中,其示意图如下:
    Hash(NODE1) = KEY1;
    Hash(NODE2) = KEY2;
    Hash(NODE3) = KEY3;

    通过上图可以看出对象与机器处于同一哈希空间中,这样按顺时针转动object1存储到了NODE1中,object3存储到了NODE2中,object2、object4存储到了NODE3中。在这样的部署环境中,hash环是不会变更的,因此,通过算出对象的hash值就能快速的定位到对应的机器中,这样就能找到对象真正的存储位置了。

  • 机器的删除与添加
    普通hash求余算法最为不妥的地方就是在有机器的添加或者删除之后会照成大量的对象存储位置失效,这样就大大的不满足单调性了。下面来分析一下一致性哈希算法是如何处理的。

  1. 节点(机器)的删除
    以上面的分布为例,如果NODE2出现故障被删除了,那么按照顺时针迁移的方法,object3将会被迁移到NODE3中,这样仅仅是object3的映射位置发生了变化,其它的对象没有任何的改动。如下图:

  2. 节点(机器)的添加
    如果往集群中添加一个新的节点NODE4,通过对应的哈希算法得到KEY4,并映射到环中,如下图:

    通过按顺时针迁移的规则,那么object2被迁移到了NODE4中,其它对象还保持这原有的存储位置。通过对节点的添加和删除的分析,一致性哈希算法在保持了单调性的同时,还是数据的迁移达到了最小,这样的算法对分布式集群来说是非常合适的,避免了大量数据迁移,减小了服务器的的压力。

3.2、如何实现平衡性?

根据上面的图解分析,一致性哈希算法满足了单调性和负载均衡的特性以及一般hash算法的分散性,但这还并不能当做其被广泛应用的原由,因为还缺少了平衡性。下面将分析一致性哈希算法是如何满足平衡性的。hash算法是不保证平衡的,如上面只部署了NODE1和NODE3的情况(NODE2被删除的图),object1存储到了NODE1中,而object2、object3、object4都存储到了NODE3中,这样就照成了非常不平衡的状态。在一致性哈希算法中,为了尽可能的满足平衡性,其引入了虚拟节点。

“虚拟节点”( virtual node )是实际节点(机器)在 hash 空间的复制品( replica ),一实际个节点(机器)对应了若干个“虚拟节点”,这个对应个数也成为“复制个数”,“虚拟节点”在 hash 空间中以hash值排列。

以上面只部署了NODE1和NODE3的情况(NODE2被删除的图)为例,之前的对象在机器上的分布很不均衡,现在我们以2个副本(复制个数)为例,这样整个hash环中就存在了4个虚拟节点,最后对象映射的关系图如下:

根据上图可知对象的映射关系:object1->NODE1-1,object2->NODE1-2,object3->NODE3-2,object4->NODE3-1。通过虚拟节点的引入,对象的分布就比较均衡了。那么在实际操作中,正真的对象查询是如何工作的呢?对象从hash到虚拟节点到实际节点的转换如下图:

“虚拟节点”的hash计算可以采用对应节点的IP地址加数字后缀的方式。例如假设NODE1的IP地址为192.168.1.100。引入“虚拟节点”前,计算 cache A 的 hash 值:
Hash(“192.168.1.100”);
引入“虚拟节点”后,计算“虚拟节”点NODE1-1和NODE1-2的hash值:
Hash(“192.168.1.100#1”); // NODE1-1
Hash(“192.168.1.100#2”); // NODE1-2

« Java并发分享 批量用户离线处理容器——绿萝 »