赞
踩
redis底层用C语句编写,redis是将数据存放到内存中
一种快照存储持久化方式,具体就是将Redis某一时刻的内存数据保存到硬盘的文件当中,默认保存的文件名为dump.rdb,可以设置间隔多长时间保存一次(Redis不用任何配置默认的持久化方案)
优点:
1:与AOF方式相比,通过rdb文件恢复数据比较快。
2:rdb文件非常紧凑,适合于数据备份。
3:通过RDB进行数据备,由于使用子进程生成,所以对Redis服务器性能影响较小。
缺点:
1:服务器断电时会丢失部分数据(数据的完整性得不到保证)
2:使用save命令会造成服务器阻塞,直接数据同步完成才能接收后续请求。
3:使用bgsave命令在forks子进程时,如果数据量太大,forks的过程也会发生阻塞,另外,forks子进程会耗费内存。
开启rdb持久化方式:
客户端可以通过向Redis服务器发送save或bgsave命令让服务器生成rdb文件,或者通过服务器配置文件指定触发RDB条件。
1:当客户端向服务器发送save命令请求进行持久化时,服务器会阻塞save命令之后的其他客户端的请求,直到数据同步完成。如果数据量太大,同步数据会执行很久,而这期间Redis服务器也无法接收其他请求,所以,最好不要在生产环境使用save命令。
2:与save命令不同,bgsave命令是一个异步操作。当客户端发服务发出bgsave命令时,Redis服务器主进程会forks一个子进程来数据同步问题,在将数据保存到rdb文件之后,子进程会退出。所以,与save命令相比,Redis服务器在处理bgsave采用子线程进行IO写入,而主进程仍然可以接收其他请求,但forks子进程是同步的,所以forks子进程时,一样不能接收其他请求,这意味着,如果forks一个子进程花费的时间太久(一般是很快的),bgsave命令仍然有阻塞其他客户的请求的情况发生。
3:服务器配置触发条件(被动触发)
就是在Redis配置文件中的save指定到达触发RDB持久化的条件,比如【多少秒内至少达到多少写操作】就开启RDB数据同步。该方式与bgsave命令类似,达到触发条件时,会forks一个子进程进行数据同步,不过最好不要通过这方式来触发RDB持久化,因为设置触发的时间太短,则容易频繁写入rdb文件,影响服务器性能,时间设置太长则会造成数据丢失。
例如我们可以在配置文件redis.conf指定如下的选项:
# 300s内至少达至10条写命令
save 300 10
之后在启动服务器时加载配置文件。
# 启动服务器加载配置文件
redis-server redis.conf
AOF持久化方式会记录客户端对服务器的每一次写操作命令,并将这些写操作以Redis协议追加保存到以后缀为aof文件末尾,在Redis服务器重启时,会加载并运行aof文件的命令,以达到恢复数据的目的。
# 开启aof机制 appendonly yes # aof文件名 appendfilename "appendonly.aof" # 写入策略,always表示每个写操作都保存到aof文件中,也可以是everysec或no appendfsync always //这种策略很安全,但是每个写请注都有IO操作,所以也很慢。 everysec:默认写入策略,每秒写入一次aof文件,因此,最多可能会丢失1s的数据。 NO:Redis服务器不负责写入aof,而是交由操作系统来处理什么时候写入aof文件。更快,但也是最不安全的选择,不推荐使用。 # 默认不重写aof文件;客户端向服务器发送bgrewriteaof命令,也可以让服务器进行AOF重写。 no-appendfsync-on-rewrite no # 保存目录 dir ~/redis/
在写入aof日志文件时,如果Redis服务器宕机,则aof日志文件文件会出格式错误,在重启Redis服务器时,Redis服务器会拒绝载入这个aof文件,可以通过以下步骤修复aof并恢复数据。
1、备份现在aof文件,以防万一。
2、使用redis-check-aof命令修复aof文件,该命令格式如下:
$ redis-check-aof -fix file.aof
3、重启Redis服务器,加载已经修复的aof文件,恢复数据。
优点:AOF只是追加日志文件,因此对服务器性能影响较小,速度比RDB要快,消耗的内存较少。
缺点:AOF方式生成的日志文件太大,即使通过AFO重写,文件体积仍然很大;恢复数据的速度比RDB慢。
混合持久化是Redis 4.0才有的功能(默认关闭)。通过aof-use-rdb-preamble配置参数控制,yes则表示开启,no表示禁用,默认是no,可通过config set修改。
当开启混合持久化时,fork出的子进程先将共享的内存副本以RDB方式写入AOF文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的AOF文件替换旧的的AOF文件。
简单的说:新的AOF文件前半段是RDB格式的全量数据,后半段是AOF格式的增量数据。
混合模式可以结合AOF和RDB的优点,能够快速加载的同时避免丢失过多的数据。
当我们执行set hello world 时,会有如下数据模型
redisObject对象非常重要,Redis对象的类型、内部编码、内存回收、共享对象等功能,都需要redisObject支持。这样设计的好处是,可以针对不同的使用场景,对5中常用类型设置多种不同的数据结构实现,从而优化对象在不同场景下的使用效率。
无论是dictEntry对象,还是redisObject、SDS对象,都需要内存分配器(如jemalloc)分配内存进行存储。jemalloc作为Redis的默认内存分配器,在减小内存碎片方面做的相对比较好。比如jemalloc在64位系统中,将内存空间划分为小、大、巨大三个范围;每个范围内又划分了许多小的内存块单位;当Redis存储数据时,会选择大小最合适的内存块进行存储。
前面说过,Redis每个对象由一个redisObject结构表示,它的ptr指针指向底层实现的数据结构,而数据结构由encoding属性决定
#首先下载一些依赖 yum -y install cpp binutils glibc glibc-kernheaders glibc-common glibc-devel gcc make gcc-c++ libstdc++-devel tcl mkdir -p /usr/local/src/redis cd /usr/local/src/redis #wget下载命令 wget http://download.redis.io/releases/redis-3.0.2.tar.gz 或者 rz 上传 tar -xvf redis-3.0.2.tar.gz cd redis-3.0.2 make make test #这个不用执行,会需要很长时间 make install #复制conf配置文件 cp /usr/local/redis-3.0.0/redis.conf /usr/local/redis/bin vi /etc/redis.conf #修改下面的内容。默认为no(可以使redis在后台运行) daemonize yes #启动 redis-server/ect/redis.conf #测试 redis-cli
slaveof <masterip> <masterport>
slaveof <masterip> <masterport>
主从复制架构中出现宕机
哨兵的作用就是对Redis的系统的运行情况的监控,它是一个独立进程。它的功能有2个:
启动哨兵进程首先需要创建哨兵配置文件:
vim sentinel.conf
输入内容:
sentinel monitor xiaoMaster 127.0.0.1 6379 1
…(配置多个,即表示多个哨兵)
说明:
xiaoMaster:监控主数据的名称,自定义即可,可以使用大小写字母和“.-_”符号
127.0.0.1:监控的主数据库的IP
6379:监控的主数据库的端口
1:最低通过票数
启动哨兵进程:
redis-sentinel ./sentinel.conf
即使有了主从复制,每个数据库都要保存整个集群中的所有数据,容易形成木桶效应。使用Jedis实现了分片集群,是由客户端控制哪些key数据保存到哪个数据库中,如果在水平扩容时就必须手动进行数据迁移,而且需要将整个集群停止服务,这样做非常不好的。Redis3.0版本的一大特性就是集群(Cluster)
设置不同的端口,6379、6380、6381(只有在单机模拟时才需要)
开启集群,cluster-enabled yes
指定集群的配置文件,cluster-config-file “nodes-xxxx.conf”
安装ruby环境
添加依赖,要注意jedis的版本为2.7.2
说明:这里的jc不需要关闭,因为内部已经关闭连接了。
- 当我们执行set abc 123命令时,redis是如何将数据保存到集群中的呢
- 计算key的插槽值:
key的有效部分使用CRC16算法计算出哈希值,再将哈希值对16384取余,得到插槽值。- 什么是有效部分?
- 如果不满足上一条情况,整个key都是有效部分;
- 首先再开启一个实例的端口为6382
- 执行脚本:./redis-trib.rb add-node 192.168.56.102:6382 192.168.56.102:6379
- 接下来需要给6382这个服务分配插槽,将6379的一部分(1000个)插槽分配给6382:
想要删除集群节点中的某一个节点,需要严格执行2步:
- 将这个节点上的所有插槽转移到其他节点上;
执行脚本:./redis-trib.rb reshard 192.168.56.102:6380
按照要求输入值即可。- 使用redis-trib.rb删除节点(格式:del-node host:port node_id)
./redis-trib.rb del-node 192.168.56.102:6380 4a9b8886ba5261e82597f5590fcdb49ea47c4c6c
- 解决
- 需要启动6个redis实例,分别是:
6379(主) 6479(从)
6380(主) 6480(从)
6381(主) 6481(从)
命令:
cd 6379/ && redis-server ./redis.conf && cd …
cd 6380/ && redis-server ./redis.conf && cd …
cd 6381/ && redis-server ./redis.conf && cd …
cd 6479/ && redis-server ./redis.conf && cd …
cd 6480/ && redis-server ./redis.conf && cd …
cd 6481/ && redis-server ./redis.conf && cd …- 创建集群,指定了从库数量为1,创建顺序为主库(3个)、从库(3个):
./redis-trib.rb create --replicas 1 192.168.56.102:6379 192.168.56.102:6380 192.168.56.102:6381 192.168.56.102:6479 192.168.56.102:6480 192.168.56.102:6481- 测试(master宕机,回复后变成slave,slave宕机,不影响集群)
使用集群需要注意的事项
1、多键的命令操作(如MGET、MSET),如果每个键都位于同一个节点,则可以正常支持,否则会提示错误。
2、集群中的节点只能使用0号数据库,如果执行SELECT切换数据库会提示错误。
参考:my.oschina.net/liughDevelop/blog/2236771
CONFIG SET slowlog-log-slower-than 6000
CONFIG SET slowlog-max-len 25
设置完成后使用 SGOWLOG GET 20 查看数据
//安装依赖
yum install epel-release
sudo yum install python-pip
pip install --upgrade pip
pip install tornado
pip install redis
pip install python-dateutil
//安装RedisLive
git clone https://github.com/nkrode/RedisLive.git
修改配置文件redis-live.conf(cd RedisLive/src)
//按照以下方式修改配置文件 { "RedisServers": [ #在此处添加需要监控的redis实例 { "server": "127.0.0.1", #redis监听地址,此处为本机 "port" : 6379, #redis端口号,可以通过lsof -i | grep redis-ser查看 redis-server端口号 "password" : "some-password" #redis认证密码,如果没有可以删除该行,注意json格式 } ], "DataStoreType" : "redis", #监控数据存储方案的配置,可选择redis或sqllite #用来存储监控数据的 Redis 实例 "RedisStatsServer": { "server" : "127.0.0.1", "port" : 6379, "password" : "some-password" }, #监控数据持久化数据存储配置 "SqliteStatsStore" : { "path": "db/redislive.sqlite" #redis数据文件 } }
./redis-monitor.py --duration=60
再次开启一个终端,进入/root/RedisLive/src目录,启动web服务
./redis-live.py
Redis 采用的是定期删除+惰性删除策略。
redis 提供 6种数据淘汰策略:
采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。对此有2种解决方法:
1:客户端角度,为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。
2:服务器角度,利用setnx实现锁
Redis作为NoSQL数据库也同样提供了事务机制。在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事务的基石。下面简要的列出Redis中事务的实现特征:
1). 在事务中的所有命令都将会被串行化的顺序执行,事务执行期间,Redis不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行。
2). 和关系型数据库中的事务相比,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。
3). 我们可以通过MULTI命令开启一个事务,有关系型数据库开发经验的人可以将其理解为"BEGIN TRANSACTION"语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。
4). 在事务开启之前,如果客户端与服务器之间出现通讯故障并导致网络断开,其后所有待执行的语句都将不会被服务器执行。然而如果网络中断事件是发生在客户端执行EXEC命令之后,那么该事务中的所有命令都会被服务器执行。
5). 当使用Append-Only模式时,Redis会通过调用系统函数write将该事务内的所有写操作在本次调用中全部写入磁盘。然而如果在写入的过程中出现系统崩溃,如电源故障导致的宕机,那么此时也许只有部分数据被写入到磁盘,而另外一部分数据却已经丢失。Redis服务器会在重新启动时执行一系列必要的一致性检测,一旦发现类似问题,就会立即退出并给出相应的错误提示。此时,我们就要充分利用Redis工具包中提供的redis-check-aof工具,该工具可以帮助我们定位到数据不一致的错误,并将已经写入的部分数据进行回滚。修复之后我们就可以再次重新启动Redis服务器了。
一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来。使用pub/sub主题订阅者模式,可以实现1:N的消息队列(生产一次消费多次)。
Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。
Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。
Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。
setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
setnx和expire合成一条指令来用
EX seconds – 设置键key的过期时间,单位时秒
PX milliseconds – 设置键key的过期时间,单位时毫秒
NX – 只有键key不存在的时候才会设置key的值
XX – 只有键key存在的时候才会设置key的值
在旧版本的redis中(指2.6.12版本之前),使用redis实现分布式锁一般需要setNX、expire、getSet、del等命令。而且会发现这种实现有很多逻辑判断的原子操作以及本地时间等并没有控制好。而在旧版本的redis中,redis的超时时间很难控制,用户迫切需要把setNX和expiration结合为一体的命令,把他们作为一个原子操作
Java环境有 Redisson 可用于生产环境集群Redis 分布式锁。在Redis的分布式环境中,Redis 的作者提供了RedLock 的算法来实现一个分布式锁。RedLock算法加锁步骤如下
获取当前Unix时间,以毫秒为单位。
依次尝试从N个实例,使用相同的key和随机值获取锁。在步骤2,当向Redis设置锁时,客户端应该设置一个网络连接和响应超时时间,这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为10秒,则超时时间应该在5-50毫秒之间。这样可以避免服务器端Redis已经挂掉的情况下,客户端还在死死地等待响应结果。如果服务器端没有在规定时间内响应,客户端应该尽快尝试另外一个Redis实例。
客户端使用当前时间减去开始获取锁时间(步骤1记录的时间)就得到获取锁使用的时间。当且仅当从大多数(这里是3个节点)的Redis节点都取到锁,并且使用的时间小于锁失效时间时,锁才算获取成功。
如果取到了锁,key的真正有效时间等于有效时间减去获取锁所使用的时间(步骤3计算的结果)。
如果因为某些原因,获取锁失败(没有在至少N/2+1个Redis实例取到锁或者取锁时间已经超过了有效时间),客户端应该在所有的Redis实例上进行解锁(即便某些Redis实例根本就没有加锁成功)。
解锁
向所有的Redis实例发送释放锁命令即可,不用关心之前有没有从Redis实例成功获取到锁.
Redis的布隆过滤器不是原生自带的,而是要通过module加载进去。Redis在4.0的版本中加入了module功能
Redis的布隆过滤器主要有两个命令:
bf.add 添加元素到布隆过滤器中:bf.add strs xy
bf.exists 判断某个元素是否在过滤器中:bf.exists strs xy
Redis中有一个命令可以来设置布隆过滤器的准确率:
bf.reserve strs 0.01 100
三个参数的含义:
第一个值是过滤器的名字。
第二个值为error_rate的值:允许布隆过滤器的错误率。
第三个值为initial_size的值:初始化位数组的大小。
布隆过滤器与BitMap类似,底层也是一个位数组。1表示有,0表示无。但布隆过滤器比BitMap需要更少的内存,因为使用多个hash算法。
如果空间越大,hash函数越多,结果就越精确,但空间效率和查询效率就会越低。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。