Redis基本使用
作为NoSQL中的一员,是一个高性能的key-value数据库,生产环境是经常会使用到的。
一、Redis简介
1.1 特性
存储结构:
redis以字典结构存储数据,并允许其他应用通过TCP协议读写字典中的内容。Redis字典中的键值除了可以是字符串,还可以是其他数据类型。redis支持的键值数据类型如下:字符串类型、散列类型、列表类型、集合类型、有序集合类型.
内存存储与持久化:
redis数据库中的所有数据都存储在内存中。redis读的速度是110000次/s,写的速度是81000次/s,相对于基于硬盘存储的数据库有明显的优势。为了避免将数据存储在内存中应为程序退出或者机器异常关机等导致内存中数据丢失的问题,redis提供了对持久化的支持,即将内存中的数据异步写入到硬盘中。
功能丰富:
redis可以为每个键设置生存时间(TTL),生存时间到期后键会自动被删除,外加支持持久化和丰富的数据类型,这些功能配合出色的性能让redis可以作为缓存系统来使用(相对于memcached,redis是单线程模型。redis是采用了线程封闭的观念,把任务封闭在一个线程,避免了线程安全问题)。。作为缓存系统,redis还可以限定内容数据占用的最大内存空间,在数据达到空间限制后可以按照一定的规则自动淘汰不需要的键。
redis的列表类型(Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作)可以用来实现队列,并且支持阻塞式读取,可以很容易的实现一个高性能的优先级队列。
redis还支持“发布/订阅”的消息模式,可以基于此构建聊天室等系统。
简单稳定:
redis直观的存储结构使其通过程序与redis交互十分简单。在redis中使用命令读取和插入数据,命令语句都很简单。
redis提供了几十种不同编程语言的客户端库,这些库很好的封装了redis命令,使程序在与redis进行交互变得更容易。
1.2 安装(Centos下)
官方下载页面:https://redis.io/download
# wget download.redis.io/releases/redis-3.2.9.tar.gz
# tar zxf redis-3.2.9.tar.gz
# cd redis-3.2.9
# make
#redis没有其他外部依赖,安装过程很简单。编译后在redis源代码目录的src文件夹中可以找到若干可执行程序。当然也可以再加个make install将这些可执行程序复制到/usr/local/bin目录中以便于执行方便。
#make install
#可执行文件说明(redis-server:redis服务器,redis-cli:命令行客户端,redis-benchmark:redis性能测试工具,redis-check-aof:AOF文件修复工具,redis-check-dump:RDB文件检查工具)
# cd /usr/redis/ #make之后,redis的启动命令和配置文件都在这个目录下面
#如果没有出现/usr/redis目录,make完之后直接把redis-3.2.9目录拷贝到指定的目录下使用就可以了(也就是不用执行make install),这种也是线上经常使用的一种方式,上面的那种就是redis的命令会拷贝到bin目录下,可以直接使用而不用加全路径。
博文来自:www.51niux.com
1.3 redis配置文件解析
在线中文文档:http://doc.redisfans.com/index.html
# cat /usr/redis/redis.conf
基本配置:
# 1k => 1000 bytes #当你需要为某个配置制定内存大小的时候,必须要带上单位,单位不区分大小写。 # 1kb => 1024 bytes # 1m => 1000000 bytes # 1mb => 1024*1024 bytes # 1g => 1000000000 bytes # 1gb => 1024*1024*1024 bytes daemonize no #默认情况下redis不是后台运行,如果要后台守护进程方式运行的话,这里改为yes。 pidfile /var/run/redis.pid #当redis作为守护进程运行的时候,pid的写入文件位置。 port 6379 #监听端口号,默认就是6379,如果你设为0,redis将不再socket上监听任何客户端链接。 bind 127.0.0.1 #默认情况下,redis是监听在0.0.0.0上面的,但是这样是危险的,漏洞已经爆出来了,所以要改为本地或者内网IP。 # unixsocket /tmp/redis.sock # unixsocketperm 755 #如果不监听端口的话,redis还支持通过unix socket方式来接收请求。可以通过unixsocket配置项来指定unix socket文件的路径,并通过unixsocketperm来指定文件的权限。 timeout 0 #指定在一个client空闲多少秒之后关闭连接(0是不设置超时) tcp-keepalive 0 #指定TCP连接是否为长连接,”侦探”信号由server端维护,长连接将会额外的增加server端的开支。默认为0.表示禁用,非0值表示开启”长连接” ;”侦探”信号的发送间隔将有Linux系统决定在多次”侦探”后, 如果对等端仍不回复,将会关闭连接,否则连接将会被保持开启.client端socket也可以通过配置keepalive选项,开启”长连接”. loglevel notice #server日志级别,合法值:debug,verbose,notice,warning 默认为notice logfile "" #指定redis日志记录方式,默认值为stdout也就是输出到屏幕 databases 16 #设定redis所允许的最大db数据库的个数,默认为16个个.redis不像mysql一样可以自定义数据库,如这里只支持0-15的索引号形式的数据库,你可以将数据写入到不同的db索引号中。 快照设置(主要涉及的是redis的RDB持久化相关的配置,让数据保存到磁盘上,即控制RDB快照功能): save 900 1 save 300 10 save 60 10000 #用来描述在多少秒期间至少多少个变更操作触发快照。例如:save 900 1 就是在900秒期间有一个key发生了变更操作就触发快照。save ""可以关闭RDB持久化功能。 stop-writes-on-bgsave-error yes #默认情况下,如果redis最后一次的后台保存失败,redis 将停止接受写操作,这样以一种强硬的方式让用户知道数据不能正确的持久化到磁盘,否则就会没人注意到灾难的发生。 如果后台保存进程重新启动工作了,redis 也将自动的允许写操作。然而你要是安装了靠谱的监控,你可能不希望 redis这样做,那你就改成no好了。 rdbcompression yes #是否启用rdb文件压缩手段,默认为yes.压缩可能需要额外的cpu开支,不过这能够有效的减小rdb文件的大小,有利于存储/备份/传输/数据恢复. rdbchecksum yes #是否对rdb文件使用CRC64校验和,默认为”yes”,那么每个rdb文件内容的末尾都会追加CRC校验和.对于其他第三方校验工具,可以很方便的检测文件的完整性 dbfilename dump.rdb #指定rdb文件的名称 dir ./ #指定rdb/AOF文件的目录位置,只能为文件夹不能为文件 主从复制设置: #slaveof <masterip> <masterport> #主从复制。指定master的ip和端口号。注意这个只需要在 slave 上配置。让一个redis实例称为另一个redis的副本。 #masterauth <master-password> #如果master需要密码认证,就在这里设置 slave-serve-stale-data yes #当一个 slave 与 master 失去联系,或者复制正在进行的时候,slave 可能会有两种表现:1) 如果为yes,slave仍然会应答客户端请求,但返回的数据可能是过时,或者数据可能是空的在第一次同步的时候 2)如果为 no ,在你执行除了 info he salveof 之外的其他命令时,slave 都将返回一个 "SYNC with master in progress" 的错误。 slave-read-only yes #从redis2.6版起,默认slaves都是只读的。注意:只读的slaves没有被设计成在internet上暴露给不受信任的客户端。它仅仅是一个针对误用实例的一个保护层。 repl-ping-slave-period 10 #slaves在一个预定义的时间间隔内发送ping命令到server。你可以改变这个时间间隔。默认为10秒。 #repl-timeout 60 #设置主从复制超时时间,这个值一定要比repl-ping-slave-period大 repl-disable-tcp-nodelay no #我们可以控制在主从同步时是否禁用TCP_NODELAY。如果开启TCP_NODELAY,那么主redis会使用更少的TCP包和更少的带宽来向从redis传输数据。 但是这可能会增加一些同步的延迟,大概会达到40毫秒左右。如果你关闭了TCP_NODELAY,那么数据同步的延迟时间会降低,但是会消耗更多的带宽。 #repl-backlog-size 1mb #设置主从复制容量大小。这个backlog是一个用来在slaves被断开连接时存放slave数据的buffer,所以当一个slave想要重新连接,通常不希望全部重新同步, 只是部分同步就够了,仅仅传递slave在断开连接时丢失的这部分数据。 #repl-backlog-ttl 3600 #如果主redis等了一段时间之后,还是无法连接到从redis,那么缓冲队列中的数据将被清理掉。我们可以设置主redis要等待的时间长度。如果设置为0,则表示永远不清理。默认是1个小时。 slave-priority 100 #当master不能正常工作的时候,Redis Sentinel会从slaves中选出一个新的master,这个值越小,就越会被优先选中,但是如果是0,意味着这个slave不可能被选中。默认优先级为100。 # min-slaves-to-write 3 # min-slaves-max-lag 10 #假如有大于等于3个从redis的连接延迟大于10秒,那么主redis就不再接受外部的写请求。上述两个配置中有一个被置为0,则这个特性将被关闭。默认情况下min-slaves-to-write为0,而min-slaves-max-lag为10。 安全设置: # requirepass foobared #我们可以要求redis客户端在向redis-server发送请求之前,先进行密码验证。当你的redis-server处于一个不太可信的网络环境中时,相信你会用上这个功能。 由于redis性能非常高,所以每秒钟可以完成多达15万次的密码尝试,所以你最好设置一个足够复杂的密码,否则很容易被黑客破解。 # rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 #这里我们通过requirepass将密码设置成“芝麻开门”。redis允许我们对redis指令进行更名,比如将一些比较危险的命令改个名字,避免被误执行。 比如可以把CONFIG命令改成一个很复杂的名字,这样可以避免外部的调用,同时还可以满足内部调用的需要 #rename-command CONFIG "" #可以禁用掉CONFIG命令,那就是把CONFIG的名字改成一个空字符串:,但需要注意的是,如果你使用AOF方式进行数据持久化,或者需要与从redis进行通信,那么更改指令的名字可能会引起一些问题。 限制设置: # maxclients 10000 #我们可以设置redis同时可以与多少个客户端进行连接。默认情况下为10000个客户端。当你无法设置进程文件句柄限制时,redis会设置为当前的文件句柄限制值减去32,因为redis会为自身内部处理逻辑留一些句柄出来。 如果达到了此限制,redis则会拒绝新的连接请求,并且向这些连接请求方发出“max number of clients reached”以作回应。 # maxmemory <bytes> #如果redis无法根据移除规则来移除内存中的数据,或者我们设置了“不允许移除”,那么redis则会针对那些需要申请内存的指令返回错误信息,比如SET、LPUSH等。 但是对于无内存申请的指令,仍然会正常响应,比如GET等。需要注意的一点是,如果你的redis是主redis(说明你的redis有从redis),那么在设置内存使用上限时, 需要在系统中留出一些内存空间给同步队列缓存,只有在你设置的是“不移除”的情况下,才不用考虑这个因素。对于内存移除规则来说,redis提供了多达6种的移除规则。他们是:volatile-lru:使用LRU算法移除过期集合中的key、 allkeys-lru:使用LRU算法移除key、volatile-random:在过期集合中移除随机的key、allkeys-random:移除随机的key、volatile-ttl:移除那些TTL值最小的key,即那些最近才过期的key、noeviction:不进行移除。针对写操作,只是返回错误信息。 # maxmemory-policy volatile-lru # 默认是volatile-lru算法,无论使用上述哪一种移除规则,如果没有合适的key可以移除的话,redis都会针对写请求返回错误信息。LRU算法和最小TTL算法都并非是精确的算法,而是估算值。所以你可以设置样本的大小。 # maxmemory-samples 3 #假如redis默认会检查三个key并选择其中LRU的那个,那么你可以改变这个key样本的数量。 追加模式设置(aof的设置): appendonly no #默认情况下,redis会异步的将数据持久化到磁盘。这种模式在大部分应用程序中已被验证是很有效的,但是在一些问题发生时,比如断电,则这种机制可能会导致数分钟的写请求丢失。 追加文件(Append Only File)是一种更好的保持数据一致性的方式。即使当服务器断电时,也仅会有1秒钟的写请求丢失,当redis进程出现问题且操作系统运行正常时,甚至只会丢失一条写请求。所以AOF机制和RDB机制可以同时使用,不会有任何冲突。 # appendfilename appendonly.aof #设置aof文件的名称 # appendfsync always appendfsync everysec # appendfsync no fsync()调用,用来告诉操作系统立即将缓存的指令写入磁盘。一些操作系统会“立即”进行,而另外一些操作系统则会“尽快”进行。 redis支持三种不同的模式: no:不调用fsync()。而是让操作系统自行决定sync的时间。这种模式下,redis的性能会最快。 always:在每次写请求后都调用fsync()。这种模式下,redis会相对较慢,但数据最安全。 everysec:每秒钟调用一次fsync()。这是性能和安全的折衷。 当fsync方式设置为always或everysec时,如果后台持久化进程需要执行一个很大的磁盘IO操作,那么redis可能会在fsync()调用时卡住。 目前尚未修复这个问题,这是因为即使我们在另一个新的线程中去执行fsync(),也会阻塞住同步写调用。 no-appendfsync-on-rewrite no #为了缓解上面提到的问题,我们可以使用上面的配置项,这样的话,当BGSAVE或BGWRITEAOF运行时,fsync()在主进程中的调用会被阻止。这意味着当另一路进程正在对AOF文件进行重构时,redis的持久化功能就失效了,就好像我们设置了“appendsync none”一样。 如果你的redis有时延问题,那么请将下面的选项设置为yes。否则请保持no,因为这是保证数据完整性的最安全的选择。 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb #允许redis自动重写aof。当aof增长到一定规模时,redis会隐式调用BGREWRITEAOF来重写log文件,以缩减文件体积。redis是这样工作的:redis会记录上次重写时的aof大小。 假如redis自启动至今还没有进行过重写,那么启动时aof文件的大小会被作为基准值。这个基准值会和当前的aof大小进行比较。如果当前aof大小超出所设置的增长比例,则会触发重写。 另外,你还需要设置一个最小大小,是为了防止在aof很小时就触发重写。如果设置auto-aof-rewrite-percentage为0,则会关闭此重写功能。 LUA脚本设置: lua-time-limit 5000 #Lua脚本的最大执行时间(以毫秒为单位)。 如果达到最大执行时间,Redis将记录脚本在最大允许时间后仍然执行,并且将开始回复具有错误的查询。 当长时间运行的脚本超过最大执行时间时,只有SCRIPT KILL和SHUTDOWN NOSAVE命令可用。 第一个可以用来停止一个还没有被称为写命令的脚本。 第二个是在脚本已经发出写入命令的情况下关闭服务器的唯一方法,但用户不想等待脚本的自然终止。 将其设置为0或负值,无限制执行而不发出警告。 SHOW log设置: Slow log 是 Redis 用来记录查询执行时间的日志系统。查询执行时间指的是不包括像客户端响应(talking)、发送回复等 IO 操作,而单单是执行一个查询命令所耗费的时间。 另外,slow log 保存在内存里面,读写速度非常快,因此你可以放心地使用它,不必担心因为开启 slow log 而损害 Redis 的速度。 slowlog-log-slower-than 10000 #它决定要对执行时间大于多少微秒(microsecond,1秒 = 1,000,000 微秒)的查询进行记录。这就就是记录查询大于10000微秒的记录。 slowlog-max-len 128 #slow log最多能保存多少条日志,slow log本身是一个 FIFO 队列,当队列大小超过 slowlog-max-len 时,最旧的一条日志将被删除,而最新的一条日志加入到 slow log ,以此类推。 事件通知设置: http://doc.redisfans.com/topic/notification.html 高级配置: zipmap优化hash,Redis会在内部自动将zipmap替换成正常的hash实现.一个对象存储在hash类型中会占用更少的内存,并且可以更方便的存取整个对象。省内存的原因是新建一个hash对象时开始是用zipmap来存储的。 hash-max-ziplist-entries 512 #配置字段最多512个 hash-max-ziplist-value 64 #配置value最大为64字节 ziplist优化list,如果redisObject的type成员值是REDIS_LIST类型的,则当该list的元素个数小于配置值list-max-ziplist-entries且元素值字符串的长度小于配置值list-max-ziplist-value则可以编码成 REDIS_ENCODING_ZIPLIST 类型存储, 否则采用 Dict 来存储(Dict实际是Hash Table的一种实现),list采用ziplist数据结构存储数据,这样做一方面为了节省内存,另一方面这种结构式顺序存储的结构,能够更好利用cpu local和预取策略。 list-max-ziplist-entries 512 #配置元素个数最多512个 list-max-ziplist-value 64 #配置value字节最大为64个 activerehashing yes #指定是否激活重置哈希,默认为开启。 对于Redis服务器的输出(也就是命令的返回值)来说,其大小通常是不可控制的。有可能一个简单的命令,能够产生体积庞大的返回数据。 另外也有可能因为执行了太多命令,导致产生返回数据的速率超过了往客户端发送的速率,这是也会导致服务器堆积大量消息,从而导致输出缓冲区越来越大,占用过多内存,甚至导致系统崩溃。 所幸,Redis设置了一些保护机制来避免这种情况的出现,不同类型的客户端有不同的限制参数。限制方式有如下两种: (1)、大小限制,当某一个客户端的缓冲区超过某一个大小值时,直接关闭这个客户端的连接; (2)、持续性限制,当某一个客户端的缓冲区持续一段时间占用过大空间时,会直接关闭客户端连接。 下面是关于客户端输出缓冲区的配置: 这些数值分别代表缓冲区软限制,硬限制和以秒为单位的超时(类似于复制缓冲区)。 client-output-buffer-limit normal 0 0 0 #对于普通客户端来说,限制为0,也就是不限制。因为普通客户端通常采用阻塞式的消息应答模式,何谓阻塞式呢? 如:发送请求,等待返回,再发送请求,再等待返回。这种模式下,通常不会导致Redis服务器输出缓冲区的堆积膨胀; client-output-buffer-limit slave 256mb 64mb 60 #对于slave客户端来说,大小限制是256M,持续性限制是当客户端缓冲区大小持续60秒超过64M,则关闭客户端连接。 client-output-buffer-limit pubsub 32mb 8mb 60 #对于Pub/Sub客户端(也就是发布/订阅模式),大小限制是8M,当输出缓冲区超过8M时,会关闭连接。持续性限制是,当客户端缓冲区大小持续60秒超过2M,则关闭客户端连接; hz 10 #Redis server执行后台任务的频率,默认为10,此值越大表示redis对"间歇性task"的执行次数越频繁(次数/秒)。"间歇性task"包括"过期集合"检测、关闭"空闲超时"的连接等,此值必须大于0且小于500。 此值过小就意味着更多的cpu周期消耗,后台task被轮询的次数更频繁。此值过大意味着"内存敏感"性较差。建议采用默认值。 aof-rewrite-incremental-fsync yes #当子进程重写AOF文件时,如果启用了以下选项,则每32MB数据生成一次文件才调用强制同步。这对于将文件更多地递增到磁盘并避免大的延迟尖峰是有用的。 INCLUDES配置: # include /path/to/local.conf # include /path/to/other.conf #当配置多个redis时,可能大部分配置一样,而对于不同的redis,只有少部分配置需要定制就可以配置一个公共的模板配置。 对于具体的reids,只需设置少量的配置,并用include把模板配置包含进来即可。 值得注意的是,对于同一个配置项,redis只对最后一行的有效,所以为避免模板配置覆盖当前配置,应在配置文件第一行使用include,当然,如果模板配置的优先级比较高,就在配置文件最后一行使用include
1.4 redis的启动
# /home/redis/redis-3.2.9/src/redis-server /home/redis/r1/redis.conf & #如这种直接将源码目录解压后放到指定的目录下面,然后再/home/redis创建N多的目录,然后直接redis-server指定redis.conf启动。
# redis-server -h #可以查看redis-server的使用方法(上面安装的时候执行了make-install就可以直接调用redis-sertver命令了)
# redis-cli -p 6379 #这是默认用redis-cli客户端-p指定端口,连接本地的6379端口。
127.0.0.1:6379> ping #ping测试命令
PONG #PONG说明是通的
127.0.0.1:6379> set k1 "hello world!" #设置键k1的值为"hello world"
OK
127.0.0.1:6379> get k1 #获取k1的值
"hello world!"
# redis-benchmark #也可以通多这个命令自己测试一下服务器本身各方面的性能
#redis是单进程模型来处理客户端的请求。对读写等事件的响应是通过对epoll函数的包装来做到的。Redis的实际处理速度完全依靠主进程的执行效率。
1.5 redis配置认证密码
#redis不设置密码运行的方式安全隐患比较大,一般都会设置密码,只有通过密码验证才能登陆。现在给bbs目录下的redis.conf配置密码,一般每个目录下的授权密码是不一样的。
# cat /data/redisdata/CMS/redis.conf
daemonize yes port 20000 dir "/data/redisdata/Bbs" pidfile "/data/redisdata/Bbs/redis.pid" logfile "/data/redisdata/Bbs/redis.log" dbfilename "dump.rdb" save 900 1 appendonly no appendfilename "appendonly.aof" appendfsync always maxmemory 8gb maxmemory-policy volatile-lru maxmemory-samples 3 slowlog-log-slower-than 10000 repl-backlog-size 64mb timeout 0 repl-timeout 240 masterauth "redis48cs" #这是redis的slave连接master同步数据所需要的密码,若master配置了密码。 requirepass "redis48cs" #这是redis设置的密码 protected-mode no
#重启redis再次尝试
# redis-cli -p 20000
127.0.0.1:20000> get info (error) NOAUTH Authentication required. 127.0.0.1:20000> exit
#通过上面的信息提示可以看到,说是没有授权,所以查看失败
# redis-cli -p 20000 -a redis48cs #-a后面的字符串就是验证密码
127.0.0.1:20000> get info (nil)
#从提示可以看到虽然没东西输出,但是已经不报授权失败的错误了。
# redis-cli -p 20000 #当然除了-a指定密码外,也可以在执行操作前进行验证
127.0.0.1:20000> config get requirepass #直接是失败的 (error) NOAUTH Authentication required. 127.0.0.1:20000> auth redis48cs #通过auth输入密码的形式通过验证 OK 127.0.0.1:20000> config get requirepass #现在再执行命令就没问题了 1) "requirepass" 2) "redis48cs"
#当然也可以在不启动redis也就是不重新加载配置文件的形式,通过命令行设置密码
127.0.0.1:20000> config set requirepass redis66cs #通过config set requirepass 在其后面跟上密码,就可以设置新的密码,不用重启redis OK 127.0.0.1:20000> config get requirepass 1) "requirepass" 2) "redis66cs"