redis 之简单介绍

时间:2021-04-14 05:21:56

Redis简介

Redis是一个开源可基于内存也可持久化的日志型、Key-Value数据库,和memcached类似但是支持的数据类型更多,数据都缓存在内存中,和memecached区别在于reids可以定期持久化数据到磁盘,并可以利用该特性实现master-slave同步。

Redis原理

redis作为内存键值对数据库,采用的单线程处理,所以不管怎样都只能使用一个CPUredis在内存存放数据是采用了hash表实现字典定位数据,字典中key保持唯一,通过对每个key进行hash,再把hash值存放于字典对应的index上,当两个key值发生hash碰撞时,在两个值中间加一个next指针这种链表的方式解决hash碰撞,字典是由两个表组成,ht[0]ht[1],字典信息都存在ht[0]中,ht[1]在进行rehash时才使用,当hash碰撞率达到阈值或者达到自动调节的阈值时,就会调用rehash使用ht[1]表重新计算keyhash值,收缩hash表或者解决hash碰撞,rehash过程如下:

1) ht[1]分配ht[0]的两倍空间

2) ht[0]的数据迁移到ht[1]

3) 清空ht[0],将ht[0]指针指向ht[1],将ht[1]指针指向ht[0]

在进行rehash时插入的数据字典信息插入到ht[1],查询、更新、删除同时在ht[0],ht[1]进行,在高并发的插入更新实例上,redis的单线程更利于减少hash碰撞。

存储类型

 字符串(string):

常用命令有setgetmsetmgetincrdecr等,普通的key/value归于该类,value值不只为字符串,也可以为数字,可以利用incrdecr进行加减操作。例如:

        127.0.0.1:6379> mset a1 12 b1 13

        OK

        127.0.0.1:6379> mget a1 b1

        1) "12"

        2) "13"

        127.0.0.1:6379> incr a1

        (integer) 13

        127.0.0.1:6379> mget a1 b1

        1) "13"

        2) "13"

        127.0.0.1:6379> 

 列表(list):

常用命令lpushlrangelinsertlremlpop等,适合场景非常多,在消息队列、消息推送上应用很广,内部采用双向链表实现,简单操作如下图:   

        127.0.0.1:6379> LPUSH listkey a b

        (integer) 2

        127.0.0.1:6379> LRANGE listkey 0 -1

        1) "b"

        2) "a"

        127.0.0.1:6379> LINSERT listkey after b bb

        (integer) 3

        127.0.0.1:6379> LRANGE listkey 0 -1

        1) "b"

        2) "bb"

        3) "a"

        127.0.0.1:6379> 

 哈希(hash):

常用命令有hsethmsethgethmgethgetall等,使用与存储对象数据,例如用户信息对象数据,类似于关系型数据一行数据,可以根据字段名查询数据出来,例如:

        127.0.0.1:6379> HMSET user username xiaozhong city chongqing age 29

        OK

        127.0.0.1:6379> HGETALL user

        1) "username"

        2) "xiaozhong"

        3) "city"

        4) "chongqing"

        5) "age"

        6) "29"

        127.0.0.1:6379> hmget user username age

        1) "xiaozhong"

        2) "29"

        127.0.0.1:6379> hget user username

        "xiaozhong"

        127.0.0.1:6379> 

 集合(set):

常用命令有saddsremspopsdiff smemberssunionsinter等,功能类似于list,但是集合数据是唯一,不能插入重复记录,集合提供了交集、并集、差集的操作命令,简单的操作如下:

        127.0.0.1:6379> SADD b1 a b c

        (integer) 3

        127.0.0.1:6379> SMEMBERS b1

        1) "a"

        2) "b"

        3) "c"

        127.0.0.1:6379> SADD b2 a c d

        (integer) 3

        127.0.0.1:6379> SINTER b1 b2

        1) "a"

        2) "c"

        127.0.0.1:6379> 


事务

关系型数据库事务的ACID四个特性,redis只支持一致性和隔离性,因为redis本来就是单线程程序,隔离性就满足了,redis提供了持久化工具,rdb持久化方式是直接刷新数据到磁盘,根据设置的机制不同,刷新频率不同,可能保存的数据不是最新数据,而在redis执行事务时也不会启动rdb持久化线程,只有事务结束之后才能执行,这样如果事务失败或者事务执行中被杀掉,不管执行了多少数据都不会保存到rdb文件,在aof持久化方式的情况下,要么一个事务全部语句都成功写入aof文件,不然在恢复时无法利用aof文件恢复数据,需要使用redis-check-aof工具修复aof文件,事务数据产生的数据也就丢失,这样也满足了事务的一致性,但是redis事务部支持原子性和持久性。

 原子性:

redis单个语句执行是原子性的,但是redis事务里面并没有提供维持原子性的机制,redis事务假如全部执行成功则提交,但是在执行途中发生宕机,kill进程的情况redis并没提供回滚等操作,不满足原子性

 持久性:

redis的事务就是一连串的命令顺序执行,并未提供持久性机制,redis的事务持久性由redis本身的持久化机制提供,但是在纯内存模式下并未持久化,采用rdb持久化方式是有时间间隔,不能在事务结束就刷新到磁盘,所以也不满足持久性特性,aof持久化机制提供了sync模式,在语句执行完就刷新日志到aof文件,但是并不会等刷新完成才完成事务,所以redis是不满足持久性

 

 事务的操作命令:

Multi:开启一个事务,后面输入的命令通过排队的方式放入一个队列中

Exec:执行事务队列中的语句

Discard:清空队列结束事务

Watch:监听某个或者多个key,在当前连接执行修改之前该key是否发生了变化,如果发生了变化执行exec命令时该事务退出,下面绿色部分就没有执行成功,因为我在其他链接对该键值做了修改

   127.0.0.1:6379> WATCH a1

        OK

        127.0.0.1:6379> MULTI

        OK

        127.0.0.1:6379> DECR a1

        QUEUED

        127.0.0.1:6379> EXEC

        (nil)

        127.0.0.1:6379> MULTI

        OK

        127.0.0.1:6379> DECR a1

        QUEUED

        127.0.0.1:6379> EXEC

        1) (integer) 13

        127.0.0.1:6379> 



Redis 持久化

Redis持久化提供了rdbaof两种方式,默认开启rdb方式。

 rdb方式:

rdb持久化方式是直接物理备份一个快照文件,在触发备份条件时,redisfork一个子进程(redis也就只有这里会出现两个进程)dump一份快照记录到临时文件,最终替换掉之前dumprdb文件。

save 900 1   #900秒内发生过1key变动触发持久化

save 300 10  #300秒内有10key发生过变动触发持久化

60 10000   #60秒内有10000key发生过变动触发持久化

rdbcompression yes #是否采用压缩的方式,占用CPU

dbfilename dump.rdb

dir /data/redis

 aof方式:

aof持久化方式类似于mysqlbinlog,采用日志追加的方式,因为一直追加可能一个key发生了一连串的修改,在恢复时事倍功半,所以redis提供了日志重做的功能,该功能也是采用rdb持久化时的方式,fork出一个子进程复制快照数据的日志生成临时aof文件,最终替换掉原有的aof文件

appendonly no #默认未开启

appendfsync everysec #刷新aof日志策略,默认everysec每秒刷一次,提供三种配置项,everysecnoalways,配置为noredis不做刷新,数据刷新交由系统负责,always则是每执行一个语句就执行刷新操作。

auto-aof-rewrite-percentage 100   #日志增长的百分比达到该值就重做日志

auto-aof-rewrite-min-size 64mb   #日志增长大小达到该值就重装日志

两种方式同时开启,在恢复时aof优先级高于rdb,只会读取aof文件,两种方式优缺点明显,rdb方式根据触发条件的定义在宕机时会丢失不等数据,占用IO少,如果保存频率高fork子进程频率也就变高,CPU占用时间就变大,aof的方式可以实时刷新数据到磁盘,保证数据安全,当然IO占用也相对大一些,在一台server上部署多个redis注意把auto-aof-rewrite-percentage设为不同值,错开fork子进程的时间

 

复制

 复制特性:

1、一个master可以有多个slave

2redis复制时masterslave都是非阻塞的,复制的同时可以执行查询等操作

3、复制具有可扩展性

4、可以用复制避免master全量备份,抵消master消耗CPU、内存、磁盘性能,在一个slave做持久化即可

 复制原理:

Redis复制利用rdb持久化特性操作,在第一次链接和重新链接时slave都会发送一个命令请求master全量dump一份rdb文件发送给slaveslave再读取恢复到内存中,再之后发生的数据变化master采用流命令的方式发送给slave

 配置:

主从配置只需要配置 slaveof  <masterip>  <masterport> 即可。

Redis高可用

Redis 官方提供了一个Redis Sentinel分布式系统,在2.8之后的版本的源码中已经直接集成,redis sentinel分布式系统在一个多redis实例的架构中运行多个sentinel进程,这些进程接收关于主服务器是否下线的信息,并使用投票的方式决定是否执行自动切换,以及选择哪个从服务器做主服务器

 特性如下:

监控:监控架构中所有主服务器及从服务器健康状态

提醒:当发现某个服务器出现问题,发送信息告知管理员或者其他应用程序

自动failover:当一个服务器出现问题时,sentinel会开启故障自动切换的操作,会将失效的主服务器的某一个从服务器升级为主服务器,并将其他从服务器的主服务器指向新的主服务器,当客户端连接主服务器时也会发送新的主服务器地址到客户端,提示客户端做切换

 

Redis键值过期管理

1) ttl key: 显示存活时间

2) Set k1 v1 ex 10/px 1000: ex存活时间10s,px 存活时间1000ms

3) 对已存在的键值添加存活时间 expire k1 10 /pexpire k1 1000 同样对应的秒和毫秒

 

Redis管理及优化

管理:

内核配置参数vm.overcommit_memory=1

禁用Linux内核特性transparent huge pages,它对内存使用和延迟有非常大的影响,echo never > sys/kernel/mm/transparent_hugepage/enabled

设置一定量的swap,如果没有swapredis实例突然消耗了大量内存,或者redis由于内存溢出会宕机,或者Linux内核OOM 会杀掉Redis进程

在使用复制时,即使master上禁用持久化,redis也会执行rdb保存

在使用复制时,master一定要开启持久化,假如未开启持久化机制,master重启之后无备份文件执行恢复,而slave会自动重连,重连之后会请求一份全新的masterrdb文件,slave数据也会被清空,要么手动执行是否连接master,或者先恢复一份完整数据到master再连接

内存优化:

限制redis使用最大内存maxmemory,在redis使用内存量达到限制时会报错,而不限制当内存使用量接近服务器内存限制大小时会失败

在写频繁的实例上设置一个合理的内存,因为在执行rdb持久化和aof日志重做时,有可能会占用两倍数据的内存,因为在这两个操作的时候否会fork一个子进程出来执行copy on write的复制,所以在执行操作期间会占用在这段时间内发生过变化的数据的等量大小。

hash-max-ziplist-entries 设置在小于这个key数量时采用紧凑堆放的方式,不使用hash字典

hash-max-ziplist-value 设置内部值不超过多少字节就采用紧凑堆放的方式,和上面的参数一起只要一个超过限制就采用hash字典的方式,hash定位更快,但是在数据量少时效率不一定比直接扫描数据内容更快

 

Redis cluster

分布式集群redis cluster ,Redis cluster异于其他的分布式架构,它没有自动路由的终端,比如codis这类分布式redis架构就有一个server做路由分发的角色,而redis cluster则没有,降低了分发的开销,但是需要client端直接定位,redis cluster 采用离散性hash,每个节点分配一些slot槽点,每个key插入时计算hash值,节点上有该hash值的槽才能插入,redis cluster 每个节点都采用master-slave的架构,所有节点互相都可以通信(见下图),所有slave节点在client端不能做任何操作,master宕机时slave自动提升为master提供服务,整个集群架构在绝大多数节点还存活的情况下都能正常使用

操作命令:

1) CLUSTER INFO 打印集群的信息  

2) CLUSTER NODES 列出集群当前已知的所有节点,以及这些节点的相关信息

3) CLUSTER MEET <ip>  <port> ip port 所指定的节点添加到集群当中

4) CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点  

5) CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点  

6) CLUSTER SAVECONFIG 将节点的配置文件保存到磁盘

7) CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点  

8) CLUSTER DELSLOTS <slot> [slot ...] 移除当前节点的一个或多个槽  

9) CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽

10) CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽,然后再进行指派

11) CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中  

12) CLUSTER SETSLOT <slot> IMPORTING <node_id> node_id 指定的节点中导入槽 slot 到本节点

13) CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate

14) CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上

15) CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量  

16) CLUSTER GETKEYSINSLOT <slot> <count> 返回 count slot 槽中的键

17) 注意:在添加删除节点时,slot槽并不会自动移动,需要手动操作,假如删除一个节点应先把节点上对应的slot槽迁移到其他节点上,添加新节点也需手动添加slot槽到节点上,删除已有的master节点,该节点对应的slave并不会自动移出或启动为master

安装配置:

1) 因为redis cluster需要ruby的依赖,先准备安装包:

a) redis-3.2.0.tar.gz

b) zlib-1.2.8.tar.gz

c) ruby-2.1.9.tar.gz

d) rubygems-2.6.4.tgz

2) 先安装zlib

a) cd zlib-1.2.8

b) ./configure

c) make && make install

3) 安装ruby

a) cd ruby-2.1.9

b) ./configure --prefix=/usr/local/ruby

c) make && make install

d) cp ruby /usr/local/bin

4) 安装rubygems:

a) cd rubygems-2.6.4

b) ruby setup.rb

c) cp bin/gem /usr/local/bin

d) gem install redis -v 3.2.0

e) #也可以直接下载gemhttp://rubygems.org/gems/redis/versions

f) #gem install -l reids-3.2.0.gem

5) 安装redis:

a) tar zxvf redis-3.2.0.tar.gz

b) cd redis-3.2.0

c) make && make install

d) cp src/redis-server /usr/local/bin

e) cp src/redis-cli /usr/local/bin

f) cp src/redis-trib.rb /usr/local/bin

6) 装备redis cluster配置:

a) mkdir /data/redis-cluster/{6380,6381,6382,6383,6384,6385}

b) #简单的集群配置

vim /data/redis-cluster/6380/6380.conf

port 6380

daemonize yes

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 50

maxmemory 100m

appendonly yes

appendfilename "appendonly-6380.aof"

aof-rewrite-incremental-fsync yes

auto-aof-rewrite-percentage 80 #该值每个节点要配置不同

dir /data/redis-cluster/6380

c) #复制配置文件到上面创建的所有文件夹,修改文件名及对应端口地址

7) #启动redis节点

a) redis-server /data/redis-cluster/6380/6380.conf

b) redis-server /data/redis-cluster/6381/6381.conf

c) redis-server /data/redis-cluster/6382/6382.conf

d) redis-server /data/redis-cluster/6383/6383.conf

e) redis-server /data/redis-cluster/6384/6384.conf

f) redis-server /data/redis-cluster/6385/6385.conf

8) #链接redis查看状态

a) >redis-cli -p 6380

b) >CLUSTER NODES

ba74a959bbeabe4932eace93695aec70fc75c773 :6380 myself,master - 0 0 0 connected

c) #cluster nodes上面介绍了可以查看到已知的所有节点信息,但是这里只显示了本节点信息,现在来用redis-trib.rb创建整个集群,如果指定了--replicas选项ip:port 按排列的顺序觉得谁是主谁是从

d) redis-trib.rb create --replicas 1 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383

>>> Creating cluster

*** ERROR: Invalid configuration for cluster creation.

*** Redis Cluster requires at least 3 master nodes.

*** This is not possible with 4 nodes and 1 replicas per node.

*** At least 6 nodes are required.

e) #提示看出,redis cluster必须不少于3master节点才能启动,上面指定了4个节点,又指定开启复制,所以不满足3master节点。

redis-trib.rb create --replicas 1 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 127.0.0.1:6385

redis-cli -p 6380

CLUSTER NODES

f) #现在就能看到每个节点信息,以及每个节点接受那些slot槽点的数据

g) 也可以用redis-trib.rb添加新节点分配slot槽到新加入的节点

i. redis-trib.rb add-node 127.0.0.1:6386 127.0.0.1:6380 第一个为新节点,第二个可以随意制定一个集群中的节点

ii. redis-trib.rb reshard 127.0.0.1:6386 可以把其他节点上的slot槽分配到新节点,也可以指定分配多少个slot槽到新节点

iii. 为新加master节点指定slave

链接到需要制定为slave的节点

redis-cli -p 6387

cluster replicate <node_id> #node_idmasterid

#在线添加slave会全量备份并且同步恢复,IOCPU、内存、网络占用都会占用攀升,谨慎操作


本文出自 “小菜鸟DBA” 博客,请务必保留此出处http://xiaozhong991.blog.51cto.com/2354914/1775139