下载: wget http://download.redis.io/releases/redis-3.0.7.tar.gz tar -xzf redis-3.0.7.tar.gz ln -s redis-3.0.7 redis cd redis make make install
安装完之后 /usr/local/bin下多了几个以redis开头可执行文件, 这些文件可以启动和停止redis、可以检测和修复redis的持久化文件, 还可以检测redis的性能 redis-server 启动redis redis-cli redis命令行客户端 redis-benchmark redis基准测试工具 redis-check-aof redisAOF持久化文件检测和修复工具 redis-check-dump redisRDB持久化文件检测和修复工具 redis-sentinel 启动redis Sentinel
防火墙端口开放: firewall-cmd --zone=public --add-port=3306/tcp --permanent 重启防火墙 firewall-cmd --reload
iptables -I INPUT -p tcp --dport 3306 -j ACCEPT
1,启动redis 有3种方法:默认配置、运行配置、配置文件启动 默认配置:redis-server 默认端口:6379
运行配置:redis-server --port 6380
运行配置文件启动:redis-server /opt/redis/redis.conf
2,redis命令行客户端 通过redis-cli连接redis、操作redis服务,
第一种是交互式方式: 通过redis-cli-h{host}-p{port}的方式,之后所有操作都是通过交互式的方式实现,不需要再执行redis-cli了 redis-cli -h 127.0.0.1 -p 6379
第二种命令方式:redis-cli-h{host} -p{port} {command} redis-cli -h 127.0.0.1 -p 6379 get hello
停止redis: redis-cli shutdown redis-cli shutdown nosave|save (注:是否持久化文件)
redis基本使用: 1,查看所有键 keys *
2,键总数: dbsize
dbsize命令在计算键总数时不会遍历所有键,而是直接获取redis内置的键总数变量, 所以dbsize时间复杂度O(1); keys 会遍历所有键,时间复杂度O(n)
3检测键是否存在 exists key 如果存在返回1,不存在返回0;
4删除键: del key 返回结果为成功删除的键的个数,假设删除不存在的键就返回0; del key1 key2
5键过期: expire key seconds
6 ttl命令会返回键的剩余过期时间,它有3种返回值: 大于等于0的整数:键剩余的过期时间
-1键没设置过期时间 -2键不存在
7 键的数据类型,如果键不存在,返回none type key
string hase list set zset
redis 高性能的原因: 1,纯内存访问,内存访问长达100纳秒 2非阻塞IO,事件监听的模式 3,单线程避免了线程切换和竞争的消耗
设置值 set hello get hello 设置值并设置过期时间 setex hello 20 world
设置值时key不存在设置成功,已存在设置失败 setnx hello world 成功返回ok,失败返回0 分布式锁 setnx
2.2字符串 值最大512MB
批量设置值 mset key value [key value ..] mset a 1 b 2 c 3
批量获取值 mget a b c 键不存在,返回nil,按键的顺序返回
计数器 incr 对值做自增操作 值不是整数,返回错误 值是整数,返回自增后的结果 键不存在,按照值为0自增
incrby 自增指定数字
decr自减 decrby 自减指定数字
append 字符串后尾追加值 append key value
strlen 字符串字节长度 中文占3个字节
redis使用场景: 1,作为mysql的缓存 2,计数器,播放次数 3,共享session, 4,限速,例如短息验证码一段时间内不能发送多少次
哈希 key field value
hset key field value hget key field hdel key field [field...] hlen key 计算field的个数 或hset key field value1 value2...
批量设置和获取field-value hmget key field [field ..] hmset key field value [field value ..]
hexists key field 存在1,不存在0
获取所有field: hkeys 命令应该叫hfields更为恰当,它返回指定哈希键所有的field hkeys key
获取所有value hvals key
自增作用域field hincrby key field hincrbyfloat key field
list:
从右添加 rpush key value 从左添加 lpush key value
查找 lrange key startIndex endIndex lrange key 0 -1
获取指定角标 lindex key index
列表长度 llen key
删除 从左弹出元素 lpop key 从右弹出元素 rpop key
删除指定元素 lrem key count value count >0 从左到右删除最多count个元素 count <0 从右到左删除count绝对值个元素 count =0 删除所有
修改指定索引元素 lset key index newValue
阻塞的pop:
blpop key timeout brpop key timeout 不为空会立刻返回
场景: 1,消息队列 redis的lpush+brpop命令组合即可实现阻塞队列, 生产者客户端使用lrpush从队列左侧插入元素,多个消费者客户端使用brpop命令阻塞式的“抢”列表尾部的元素, 多个客户端保证了消费的负载均衡和高可用
集合set:不允许重复 添加元素 sadd key element....
删除元素 srem key element ...
统计元素个数 scard key (注:直接用redis内部变量)
判断元素是否在集合中 sismember key element
随机返回指定个数元素, 不删除 srandmember key [count]
从集合随机弹出元素,会删除 spop key
获取所有元素 smembers key
有序集合 zadd key score member
=======
bitMap
通过bit位来表示key的值或状态,Redis 从 2.2 版本之后新增了setbit, getbit, bitcount 等几个 bitmap 相关命令。
语法:SETBIT key offset value
bit 的默认值是 0,那么 BitMap 在实际开发的运用呢?这里举一个例子:储存用户在线状态。这里只需要一个 key,然后把用户 ID 作为 offset,如果在线就设置为 1,不在线就设置为 0。实例代码:
//设置在线状态
setBit('online', userId, 1);
//设置离线状态
setBit('online', userId, 0);
//获取状态
getBit('online', userId);
//获取在线人数
bitCount('online');
======
Geo
1,geoadd:将给定的空间元素(纬度,经度,名字)添加到指定的键里面,这些数据会以有序集合的形式被存储在键里面。
geoadd online 13.32 38.26 driverId
2,geopos: 从键里面返回给定位置元素的位置(经度和纬度)
geopos online driverId
3,geodist: 返回给定位置之间的距离,默认单位:m
geodist online driverId1 driverId2
4,georadius
georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count]
以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。距离单位和上面的一致,其中后面的选项:
WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。距离的单位和用户给定的范围单位保持一致。 WITHCOORD: 将位置元素的经度和维度也一并返回。 WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。这个选项主要用于底层应用或者调试, 实际中的作用并不大。
redis> GEORADIUS online15 37 200 km WITHDIST 1) 1) "Palermo" 2) "190.4424" 2) 1) "Catania" 2) "56.4413"
4删除地理位置:
jedisCluster.zrem(key, member)
复制配置有3种方式: 1,在配置文件中加入slaveof {masterHost} {masterPort} redis启动生效 2,redis—server启动命令后加入--slaveof {masterHost} {masterPort} 3,redis在运行中,slaveof {masterHost} {masterPort}动态配置
slaveof本身是异步的 复制搭建成功后,可以使用info replication 查看复制相关状态
在从节点执行slaveof no one 来断开和主节点的复制关系。注:不会删除从节点上的所有数据
切换主节点: slaveof {newMasterHost} {newMasterPort} 注:会删除从节点上的所有数据
对于数据比较重要,主节点会通过设置requrepass参数进行密码验证,这时所有的的客户端访问必须使用auth命令 实行校验。配置从节点masterauth与主节点密码保持一致。
只读: 默认情况下,从节点使用slave-read-only=yes配置为只读模式。由于复制是从主节点到从节点,对于从节点的任何修改,主节点不会感知;
传输延迟: 主从节点一般部署在不同机器上,复制时的网络延迟就成为需要考虑的问题,redis为我们 了repl-disable-tcp-nodelay参数用于控制TCP-NODELAY,默认关闭,说明如下: 当关闭时,主节点产生的命令数据无论大小都会及时地发送从节点,这样主从之间延迟 会变小,但增加了网络带宽的消耗。使用于主从之间网络环境良好的场景,如同机房; 当开启时,主节点会合并较小的tcp数据包从而节省带宽。默认发送时间间隔取决于linux内核,一般认为40毫秒。 这种配置节省了带宽但增大主从节点的延迟。使用于主从网络环境复杂或带宽紧张的场景,如跨机房部署;
部署主从节点时需要考虑网络延迟、带宽使用率、防灾级别等因素,如要求低延迟时建议同机架或同机房部署并关闭repl-disable-tcp-nodelay; 如考虑高容灾性,可以同城跨机房部署并开启repl-disable-tcp-nodelay.
=========== redis 持久化: RDB持久化时把当前进程数据生成快照保存到硬盘的过程。触发RDB持久化过程分为手动触发和自动触发。 1,触发机制 手动触发分别对应save和bgsave命令: save命令:阻塞当前redis服务器,直到RDB过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用。运行save命令对应的日志如下: * DB saved on disk bgsave命令:redis 进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。运行bgsave命令 对应的redis 日志如下: *Background saving started by pid 3151 *DB save on disk *RDB:0 MB of memory userd by copy-on-write *Background saving terminated with success
显然bgsave命令是针对save阻塞问题做的优化。因此redis 内部所有的的涉及RDB的操作都采用bgsave 的方式,而save 命令已经废弃。 redis 内部自动触发: 1,从节点执行全量复制,主节点会自动触发bgsave生成的rdb文件并发送给从节点。 2,默认情况下执行shutdown 时,如果没有开启aof持久化功能则自动执行bgsave.
RDB流程: 1执行bgsave命令,redis 父进程判断档期是否存在正在执行的子进程,如果存在直接返回; 2父进程执行fork操作创建子进程,fork操作会阻塞父进程,通过info stats命令查看
指定持久化文件启动redis redis-server --port 6080 --dir /soft
集群 yum -y install gcc gcc-c++ && yum -y install cmake && yum -y install ncurses-devel && yum -y install autoconf && yum -y install perl perl-devel
mkdir soft &&cd soft wget http://download.redis.io/releases/redis-3.0.7.tar.gz tar -xzf redis-3.0.7.tar.gz ln -s redis-3.0.7 redis cd redis make make install
创建3个目录 conf 配置 data 数据 log 日志
mkdir /usr/local/bin/conf && mkdir /usr/local/bin/data && mkdir /usr/local/bin/log
cp redis.conf /usr/local/bin/conf/redis-6381.conf cp redis.conf /usr/local/bin/conf/redis-6382.conf cp redis.conf /usr/local/bin/conf/redis-6383.conf cp redis.conf /usr/local/bin/conf/redis-6384.conf cp redis.conf /usr/local/bin/conf/redis-6385.conf cp redis.conf /usr/local/bin/conf/redis-6386.conf 改端口 redis-6381.conf 每个节点配置如下: port 6381 #配置redis作为守护进程运行 daemonize yes #开启集群模式 cluster-enabled yes #节点超时 ,毫秒 cluster-node-timeout 15000 #集群内部配置文件 cluster-config-file "nodes-6381.conf" #日志文件: logfile "./log/redis-6381.log"
appendonly yes
启动各节点 cd /usr/local/bin redis-server ./conf/redis-6381.conf redis-server ./conf/redis-6382.conf redis-server ./conf/redis-6383.conf redis-server ./conf/redis-6384.conf redis-server ./conf/redis-6385.conf redis-server ./conf/redis-6386.conf
开放各自端口 firewall-cmd --zone=public --add-port=6381/tcp --permanent
firewall-cmd --zone=public --add-port=6382/tcp --permanent firewall-cmd --zone=public --add-port=6383/tcp --permanent firewall-cmd --zone=public --add-port=6384/tcp --permanent firewall-cmd --zone=public --add-port=6385/tcp --permanent firewall-cmd --zone=public --add-port=6386/tcp --permanent
firewall-cmd --zone=public --add-port=16381/tcp --permanent firewall-cmd --reload
iptables -I INPUT -p tcp --dport 16381 -j ACCEPT
节点加入集群(节点握手) 在节点6381: redis-cli -h 127.0.0.1 -p 6381
查看节点信息 cluster nodes
cluster info
ruby 环境 wget https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz tar xvf ruby-2.3.1.tar.gz cd ruby-2.3.1 ./configure -prefix=/usr/local/ruby make make install cd /usr/local/ruby sudo cp bin/ruby /usr/local/bin sudo cp bin/gem /usr/local/bin
安装rubygem redis依赖 wget http://rubygems.org/downloads/redis-3.3.0.gem
gem install -l redis-3.0.7.gem gem list --check redis gem
如果报错缺少: cannot load such file -- zlib yum -y install zlib-devel cd ruby-2.3.1/ext/zlib ruby ./extconf.rb make make install
安装redis-trib.rb
cp /soft/redis-3.0.7/src/redis-trib.rb /usr/local/bin
cd /usr/local/bin ./redis-trib.rb 执行redis-trib.rb 命令确认环境是否正确
创建集群 ./redis-trib.rb create --replicas 1 192.168.211.132:6384 192.168.211.133:6385 192.168.211.134:6386 192.168.211.128:6381 192.168.211.130:6382 192.168.211.131:6383
replicas 1 指每个主节点配置多少个从节点,这里1代表每个主节点配置一个从节点 先主后从
报错:槽被占用 ERR Slot 0 is already busy (Redis::CommandError) 登录每个节点: 清除:flushall 和cluster reset 或者删除节点配置文件,重启
手工集群命令 加入集群: cluster meet otherIP other port cluster meet 192.168.211.130 6382 分配槽命令: redis-cli -h 127.0.0.1 -p 6380 cluster addslots {0...5461} 让节点成为从节点: 在节点执行cluster replicate {nodeId} nodeId:为主节点节点id
集群完整性检查: redis-trib.rb check 127.0.0.16381
集群扩容: 1,准备节点(和之前一样) 2,加入集群
( 不借助第三方工具: 在集群内,任意节点执行 cluster meet 新节点ip 新节点端口 在:192.168.211.128 6381 cluster meet 192.168.211.135 6387 cluster meet 192.168.211.136 6388 )
线上建议用redis-trib.rb add-node 新节点ip:port 集群任意ip:port redist-trib.rb add-node 192.168.137:6387 192.168.136:6386
3,迁移槽和数据
流程:1目标节点准备导入槽 ,2源节点准备导出槽 , 3批量获取源节点槽对应的键 , 4导入给目标节点,5通知所有主节点,该槽已指派给了目标节点
使用第三方: 1)redis-trib.rb reshard host:port --from <source-node-id> --to <target-node-id> --slots <totalCount> --yes --timeout <arg> --pipeline <arg>
参数说明: host:port 必传,集群内任意节点地址 --from :源节点id ,多个逗号隔开 --to:目标节点id,只有一个 --slots:需要迁移槽的总数量 --yes:是否需要输入yes确认后再执行 --timeout: 控制每次迁移操作的超时时间,默认60 000毫秒 --pipeline:控制每次批量迁移键的数量,默认 10
redis-trib.rb reshard 192.168.211.130:6382 //输入迁移槽数量 how many slots do you want to move (from 1 to 16384)?1460 //输入目标节点id what is the receiving node ID? afab09215f07d426d754c930281d49b313875576 //输入源节点 done 结束 Source node #:7870e122c4f6b9cd9af8542fe665310b8c5ee3ce Source node #:e5c077acbfd838c443810808501ee38e71c38639 Source node #:e4acefc31e4c83d71fe53e5bccbdaac8452ed21c Source node #:done
确认无误后输入yes
注:由于槽用于hash运算本身顺序没有意义,因此无须强制要求节点负责槽的顺序
迁移之后使用redis-trib.rb rebalance 命令检查节点之间槽的均衡性,如果不均衡,会自动调节均衡 redis-trib.rb rebalance 192.168.211.128:6381
2)添加从节点 在还没有主节点的节点执行: cluster replicate 主节点id 在6388 节点: cluster replicate afab09215f07d426d754c930281d49b313875576
收缩集群: 流程: 下线节点 ,1节点持有槽 ,迁移槽到其他节点,通知其他节点忘记下线节点 2节点不持有槽 ,通知其他节点忘记下线节点
1,迁移槽和数据
把6383 和6386下线 6383是主节点,持有槽(12288-16383) 6386是从节点
把6383 节点均匀迁移槽到其他3个主节点,每个节点都迁移1365个槽
目标节点每次只能写一个,所以 redis-trib.rb reshard 要执行3次 redis-trib.rb reshard 192.168.211.128:6381 和扩容时一样道理
注:如果主节点不持有槽,从节点会自动指向其他主节点 建议迁移槽时,主节点剩余一个槽,把从节点下线之后再迁移主节点槽
2,让其他忘记节点 cluster forget {downNodeId} 线上不建议用这命令, 线上用redis-trib.rb del-node {host:port} {downNodeId}
redis-trib.rb del-node内部伪代码: 1,判断是否还持有槽,如果有,下线失败退出
2, 遍历所有节点:如果下线节点有从节点,则把从节点指向其他主节点 发送cluster forget 忘记节点命令 建议先下线从节点,防止不必要的全量复制
命令如下:
redis-trib.rb del-node 192.168.211.128:6381 从节点id redis-trib.rb del-node 192.168.211.128:6381 主节点id
redis-trib.rb del-node 192.168.211.128:6381 855907771dfcb29cc26a405ba2a59e9be8a375aa
redis-trib.rb del-node 192.168.211.128:6381 7870e122c4f6b9cd9af8542fe665310b8c5ee3ce
查看key所在的槽: cluster keyslot key
故障转移: 故障发现: 主观下线:某个节点认为另一个节点不可用,即下线状态,这个状态并不是最终的。 客观下线:集群内多个节点认为不可以用,真正下线,需要对该节点进行故障转移。