Redis是一个开源的,使用C语言编写的、支持网络交互的、可基于内存也可持久化的key-value数据库。
1.Redis的持久化
Redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。
RDB,简单说就是在不同的时间点,将Redis存储的数据生成快照并存储到磁盘等介质上。
AOF,则是换了一个角度来实现持久化,那就是将Redis执行过的所有写指令记录下来,在下次Redis重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复。
如果RDB和AOF同时使用,Redis重启的话,则会优先采用AOF方式来进行恢复,这是因为AOF方式的数据恢复完整度更高。
(1)RDB
Redis在进行数据持久化过程中,会先将数据写到一个临时文件中,待持久化过程都结束了,才会用这个临时文件替换上次久化好的文件。正是这种特性,让我们可以随时进行备份,因为快照文件总是完整可用的。对于RDB方式,Redis会单独创建一个子进程来进行持久化,而主进程是不会进行任何IO操作的,这样就确保了Redis极高的性能。
如果对于数据恢复的完整性不是非常敏感,RDB方式要比AOF更加高效,如果对数据的完整性非常敏感,当Redis故障时,仍然会有近5分钟的数据丢失。
(2)AOF
默认的AOF持久化策略是每秒钟fsync一次(fsync是指把缓存中的写指令记录到磁盘中),因为在这种情况下,Redis仍然可以保持很好的处理性能、即使Redis故障,也只会丢失最近1秒的数据。
如果在追加日志时,恰好遇到磁盘空间满、inode满或断电等情况导制日志写入不完整,也没有关系,Redis提供了redis-check-aof工具,可以用来进行日志修复。
Redis提供了AOF文件重写机制,即当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。
在进行AOF重写时,仍然采用先写临时文件,全部完成后再替换的流程。如果直接执行bgrwriteaof命令,那么Redis会生成一个全新的AOF文件。
在重写即将开始之际,Redis会创建一个“重写子进程”,这个子进程会首先读取现有AOF文件,并将其包含的指令进行分析压缩并写到一个临时文件中。与此同时,主工作进程会将新接收到写指令一边累积到内存缓存区中,一边继续写入原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。当“重写子进程“完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中。当追加结束后,Redis就会用新的AOF文件来代替旧的AOF文件,之后再有新的写指令,就都会追加新的AOF文件中了。
2. 主从
Redis支持主从同步,而且也支持一主多从以及多级比结构。在主从架构中,从服务器通常被设置为只读模式,这样可以避免从服务器的数据被误修改。但是从服务器仍然可以接受CONFIG等指令,如果必须将从服务器直接暴露到不安全的网络环境中,可以考虑给重要指令进行重命名,来避免被外人执行。
在主从架构中,可以考虑关闭服务器的数据持久化功能,只让从服务器进行持久化,这样可以提高主服务器的处理性能。
Redis的主从同步是异步进行的,这意味着主从同步不会影响主逻辑,也不会降低Redis的处理性能。从服务顺向主服务器发出SYNC指令,当主服务器接受到此命令后,就会调用BGSAVE指令来创建一个子进程专门进行数据持久化工作,也就是将主服务器的数据写入RDB文件中。在BGSAVE指令执行完成后,主服务器会将持久化好的RDB文件发送给从服务器,从服务器接到此文件后会将其存储到磁盘上,然后再读取到内存中。这个动作完成后,主服务器会将这段时间缓存的写指令再以Redis协议的格式发送给从服务器。
3.事务
(1)MULTI用来组装一个事务
(2)EXEC用来执行一个事务
(3)DISCARD用来取消一个事务
(4)WATCH用来监视一些key,一旦这些key在事务执行之前被改变,则取消事务的执行。支持同时监视多个key。
4.配置
Redis配置文件被分成几大块区域
(1)通用(general)
- daemonize配置项可以控制Redis的支行形式,默认情况下,Redis并不是以daemon形式来运行的。当以daemon形式运行时,Redis会生成一个pid文件,默认会生成在/var/run/redis.pid,也可以通过pidfile来指定文件生成的位置。
- 默认情况下,Redis会响应本机所有可用网卡的连接请求,可以通过bind配置项来指定要绑定的IP。
- Redis默认服务端口是6379,可以通过port配置项来修改,如果端口设置为0的话,Redis便不会监听端口了。
- Redis还支持unix socket方式来接收请求,可以通过unixsocket配置项来指定unix socket文件路径,并通过unixsocketperm来指定文件的权限。
- 当一个redis-client一直没有请求发向server端,那以server端有权主动关闭这个连接,可以通过timeout来设置空闲超时时限,0表示永不关闭。
- TCP连接策略,可以通过tcp-keepalive配置项来进行设置,单位为秒,如果设置为0,则不会进行保活检测。
- 通过loglevel配置项设置日志等级,共分四级,即debug verbose notice warning
- 通过logfile配置项来设置文件的生成位置。如果设置为空,则Redis会将日志输出到标准输出。在daemon情况下,日志会被写到/dev/null中。
- 如果希望日志打印到syslog中,通过syslog-enabled来控制。另外,syslog-ident还可以让你指定syslog里的日志标志。
- 通过databases可以设置数据库的总数量。数据库编号从0开始。
(2)快照(snapshotting)
- 如果用户开启了RDB,那么Redis持久化失败时,Redis会停止接受所有的写请求,也可以使用stop-writes-on-bgsave-error来关闭这个功能。
- 对于存储到磁盘的快照,可以设置是否进行压缩存储,如果是的知,Redis会采用LZF算法进行压缩。可以使用rdbcompression配置项来关闭这个功能。
- 在存储快照后,可以使用CRC64算法来进行数据检验,但是这样会增加性能消耗,可以使用rdbchecksum 配置项来关闭此功能。
- 可以通过dbfilename来设置快照文件的名称。
- 可以通过dir来设置快照文件存放在路径。
(3)复制(replication)
- 如果主Redis设置了验证密码的话(使用requirepass来设置),则在从Redis的配置中要使用masterauth来设置检验密码。
- 通过slave-read-only来设置从Redis是否只读。
- 只读的从Redis并不适合直接暴露给不可信的客户端,可以使用rename-command指令来将一些可能有破坏办的命令重命名。
- 从Redis会周期性的向主Redis发PING包,可以通过repl-ping-slave-period指令控制其周期。其超时设置可以通过repl-ping-slave-period设置,不过要确保这个时限比repl-ping-slave-period的值要大。
- 可以通过repl-disable-tcp-nodelay来设置 主从同步时是否禁用TCP_NODELAY,如果开启了TCP_NODEPLAY,那么主Redis会使用更少的TCP包和更少的带宽来向从Redis传输数据。但是这可能会增加一些同步的延迟,大概会达到40毫秒。
- 通过repl-backlog-size设置同步队列长度,队列长度(backlog)是主Redis的一个缓冲区,在与从Redis断开连接期间,主Redis会用这个缓冲区来缓存应该发给从Redis的数据。这样的话,当从Redis重新连接上之后,就不必重新全量同步数据。
- 如果主Redis等待了一段时间之后,还是无法连接上从Redis,那么缓冲队列中的数据将被清理掉,这个时间可以通过repl-backlog-ttl设置,如果设置为0,则表示永不清理。
- 在众多的从Redis中可以设置优先级,在主Redis不正常的情况下,优先级高的从Redis将会升级为主Redis,slave-priority,如果设置为0,这个从Redis永远也不会被选中。
- 假如主Redis发现有超过M个从Redis的连接延时超过N秒,那么主Redis就停止接受外来的写请求。如果min-slaves-to-write 3, min-slaves-max-lag 10,那么有3个从Redis的连接延迟超过10秒,那么主Redis就不再接爱外部的写请求。上述两个配置中有一个被置为0,则这特性将被关闭。
(4)安全(security)
- requirepass 可以设置密码验证。
- rename-command如果把命令改为空安符串,就是禁用掉CONFIG命令。
(5)限制(limits)
- maxclients,设置Redis同时可以与多少个客户端进行连接,当你无法设置进程文件句柄限制时,Redis会设置为当前的文件句柄限制值减去32,因为Redis会为自身处理逻辑留一些句柄。
- maxmemoery <bytes> ,设置Redis可以使用的内存理,一旦到达内存使用上限,Redis会尝试移除内部数据,移除规则可以通过maxmemory-policy来指定。
- maxmemory-policy ,可以是volatile-lru(LRU算法移除过期集合中的key)、allkey-lru(使用LRU算法移除key)、volatile-random(在过期集合中移除随机的key)、allkeys-random(移除随机的key)、volatile-ttl(移除那此TTL值最小的key)、noeviction(不进行移除,只是返回错误信息)
(6)追加模式(append only mode)
- appendfilename,设置aof文件的名称 。
- appendfsync,aof缓存的模式(no=让操作系统自行决定,always=每次写请求,everysec=每秒)
- no-appendsync-on-rewrite,如果后台持久化需要一个很大的IO操作,那么Redis可能会在fsync调用时卡住,使用这引配置项。
- auto-aof-rewrite-percentage和auto-aof-rewrite-min-size,用于Redis自动启动重写。
(7)LUA脚本(lua scripting)
- lua-time-limit(ms),设置lua脚本的最大运行时间,如果设置为0或负数,则不会有时间限制。
(8)慢日志(slow log)
慢日志是用于Redis记录那些超过指定查询时间的日志,执行的时间不包括和客户羰的IO操作和响应时间等,而只是Redis执行命令的时间。针对慢日志,可以设置两个参数,一个是执行时长,另一个是长度。slowlog-log-slower-than, slow-max-len。
(9)事件通知(event notification)
Redis支持”主配置文件中引入外部配置文件“
include /path/to/other.conf
5.Redis数据类型
1.String
这是简单的key-value类型,value其实不仅是String,也可以是数字。
应用场景:可以完全实现目前Memcached的功能,并且效率更高。
- 获取字符串长度。
- 往字符串append内容。
- 设置和获取字符串的某一段内容。
- 设置及获取字符串的某一位(bit)
- 批量设置一系列字会串的内容。
实现方式:String在Redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr、decr等操作进会转成数值进行计算,此时redisObject的encoding字段为int.
2.Hash
需要注意,Redis提供了hgetall可以直接取得全部的属性数据,但是如果内部Map的成员很多,那么涉及到遍历整个内部Map的操作,由于Redis单线程模型的缘故,这个遍历可能会比较耗时,而令其它客户端的请求完全不响应。
实现方式:Redis Hash对应的Value内部实现就是一个HashMap,实际这里会有两种不同实现,这个Hash的成员比少时Redis为节省内存会采用类似一维数组的方式秋紧凑存储,而不会采用真正的HashMap结构,对应的redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。
3.List
应用场景:列表和队列。
Redis的list的实现为一个双向链表,即可以支持查找和遍历,更方便操作,不过带了部分额外的内存开销。
4.Set
应用场景:排重列表。
实现方式:set的内部实现是一个value永远为null的HashMap,实际就是通过计算hash方式来快速排重。
5.Sort Set
可以通过用户额外提供一个优先级(score)的参数来为成员排序。
实现方式:内部使用HashMap和跳表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳表里存放的是所有成员,使用跳表的结构可以获得比较高的查找效率,并且在实现上比较简单。
6.Pub/Sub
就是发布和订阅,在Redis中,可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行消息发布后,所有订阅它的客户端都会收到相应的消息。
6.Redis实际应用场景
(1)显示最新的项目列表
LPUSH lastest.comments <ID>
LTRIM latest.comments 0 5000可以裁剪为指定的长度。
(2)删除和过滤
可以使用LREM来删除评论。
(3)排行榜相关
模式是这样的,每次获得新得分时,ZADD leaderboard <score> <username>
得到前100名高分用户:ZREVRANGE leaderboard 0 99
用户的全球排名:ZRANK leaderboard <username>
(4)计数
Redis是一个很好的计数器,有了原子递增,可以放心的加上各种计数,用GETSET重置,或者是让它们过期。
Redis查询当前库有多个key
info可以看到所有库的key数量。
dbsize则是当前库key的数量。
keys * 数据量小的可以,大的慎用。
远程连接redis
redis-cli.exe -h xx.xx.xx.xx -p port
最后欢迎大家访问我的个人网站:1024s