4.基本操作
1.启动服务,连接redis
1.启动服务 [root@localhost ~]# redis-server /usr/local/bin/xuconfig/redis.conf 2.连接redis [root@localhost bin]# redis-cli -p 63792.redis-benchmark压力测试工具
例如 [root@localhost bin]# redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000redis默认有16个数据库
默认使用的是第0个
可以使用select n 进行切换数据库
redis是单线程的!
明白redis是很快的,官方表示,redis是基于内存操作,cpu不是redis性能瓶颈,redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就没必要使用多线程
Redis是c语言写的,官方提供的数据为100000+的QPS,完全不比同样是使用key-value的Memecache差!!
redis为什么单线程还能这么快?
1.误区1:高性能的服务器一定是多线程的?
2.误区2:多线程(cpu上下文会切换!)一定比单线程效率高?
核心:redis是将所有的数据全部放在内存中的,所以说使用单线程操作效率就是最高的,多线程(cpu上下文会切换,耗时的操作!!!),对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在同一个cpu上的,在内存情况下,这个就是最佳的方案
[root@localhost bin]# redis-cli 127.0.0.1:6379> select 2 # 切换数据库 OK 127.0.0.1:6379[2]> set cgl ssb # 存键值对 OK 127.0.0.1:6379[2]> get cgl # 取值 "ssb" 127.0.0.1:6379[2]> keys * # 查看所有的键 1) "cgl" 127.0.0.1:6379[2]> flushdb # 清空数据库 OK 127.0.0.1:6379[2]> keys * (empty list or set) 127.0.0.1:6379[2]> select 0 OK 127.0.0.1:6379> keys * #第一个数据库默认的值 1) "key:__rand_int__" 2) "myset:__rand_int__" 3) "counter:__rand_int__" 4) "mylist" 127.0.0.1:6379> flushall # 清空全部的数据库 OK 127.0.0.1:6379> set name xjp OK 127.0.0.1:6379> set age 20 OK 127.0.0.1:6379> exists name # 查看当前的键是否存在 (integer) 1 127.0.0.1:6379> move name 1 # 将当前库的name键移到数据库1中 (integer) 1 127.0.0.1:6379[1]> del name # 删除当前库的某个键 (integer) 1 127.0.0.1:6379> set name xjp OK 127.0.0.1:6379> keys * 1) "name" 2) "age" 127.0.0.1:6379> expire name 10 # 定时任务 让name10s后失效 (integer) 1 127.0.0.1:6379> ttl name # 查看name还有多长时间失效 (integer) 4 127.0.0.1:6380> exists myset # 查看某个键是否存在 (integer) 1 127.0.0.1:6379> type name # 查看key对应值的类型 string 127.0.0.1:6379>string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。
string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。
string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。
######################################################################################## 127.0.0.1:6379> keys * 1) "name" 127.0.0.1:6379> set age 20 OK 127.0.0.1:6379> get name "xjp" 127.0.0.1:6379> append name hello # 从某个key中追加字符串,如果当前key不存在,相当于setkey (integer) 8 127.0.0.1:6379> get name "xjphello" 127.0.0.1:6379> append name youarecguoliangfarther (integer) 30 127.0.0.1:6379> get name "xjphelloyouarecguoliangfarther" 127.0.0.1:6379> strlen name # 获取某个key对应的值的长度 (integer) 30 ######################################################################################## i++; 步长i+= 127.0.0.1:6379> set views 0 OK 127.0.0.1:6379> get views "0" 127.0.0.1:6379> incr views # 每执行一次 views值+1 相当于i++ (integer) 1 127.0.0.1:6379> incr views (integer) 2 127.0.0.1:6379> incr views (integer) 3 127.0.0.1:6379> get views "3" 127.0.0.1:6379> decr views # 每执行一次 views值-1 相当于i-- (integer) 2 127.0.0.1:6379> decr views (integer) 1 127.0.0.1:6379> incrby views 10 # 对当前的views的值+10 (integer) 11 127.0.0.1:6379> decrby views 10 # 对当前的views的值-10 (integer) 1 127.0.0.1:6379> ######################################################################################## 127.0.0.1:6379> get name "xjphelloyouarecguoliangfarther" 127.0.0.1:6379> getrange name 1 5 # 截取字符串[1,5] "jphel" 127.0.0.1:6379> getrange name 0 -1 "xjphelloyouarecguoliangfarther" # 获取所有的字符串 127.0.0.1:6379> set key1 abcdefg OK 127.0.0.1:6379> get key1 "abcdefg" 127.0.0.1:6379> setrange key1 1 xx # 替换指定位置开始的字符串 (integer) 7 127.0.0.1:6379> get key1 "axxdefg" ####################################################################################### # setex (set with expire) # 设置过期时间 # setnx (set if not exist) # 不存在再设置,在分布式锁中会常常使用 127.0.0.1:6379> setex key2 30 hello # 修改key2的值为hello 并在30s后过期,如果key2不存在则创建 OK 127.0.0.1:6379> get key2 "hello" 127.0.0.1:6379> ttl key2 # 查看key2还有多久过期 (integer) 10 127.0.0.1:6379> setnx mykey redis # 如果mykey不存在 则创建,存在则返回0 (integer) 1 127.0.0.1:6379> keys * 1) "mykey" 2) "views" 3) "age" 4) "name" 5) "key1" 127.0.0.1:6379> ttl key2 (integer) -2 127.0.0.1:6379> setnx mykey mongoDB (integer) 0 127.0.0.1:6379> get mykey "redis" 127.0.0.1:6379> ###################################################################################### # 一次性操作多个key 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 OK 127.0.0.1:6379> keys * 1) "k2" 2) "k3" 3) "k1" 127.0.0.1:6379> mget k1 k2 k3 1) "v1" 2) "v2" 3) "v3" 127.0.0.1:6379> ######################################################################################## # 存储对象 127.0.0.1:6379> set user:1 {name:zhangsan,age:3} # 第一种方式, OK 127.0.0.1:6379> get user:1 "{name:zhangsan,age:3}" 127.0.0.1:6379> mset user:2:name lisi user:2:age 20 # 第二种方式 OK 127.0.0.1:6379> keys * 1) "user:1" 2) "user:2:age" 3) "user:2:name" 127.0.0.1:6379> ###################################################################################### #getset 先get后set 如果没有会创建 如果有则替换 127.0.0.1:6379> getset db redis # 由于没有db这个键,所以先返回nil,后执行set (nil) 127.0.0.1:6379> get db "redis" 127.0.0.1:6379> getset db Mongodb "redis" 127.0.0.1:6379> get db "Mongodb" 127.0.0.1:6379>Redis hash 是一个键值(key=>value)对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
127.0.0.1:6379> hmset user:1 name xjp age 20 # 在同一个对象中创建多个键值对 OK 127.0.0.1:6379> hmget user:1 name age 1) "xjp" 2) "20" 127.0.0.1:6379> hset myshash field 5 # 创建一个hash对象 (integer) 1 127.0.0.1:6379> hget myshash field # 获取值 hgetall获取所有值 "5" 127.0.0.1:6379> hincrby myshash field 1 # 执行一次,值+1 (integer) 6 127.0.0.1:6379> hincrby myshash field 1 (integer) 7 127.0.0.1:6379> hincrby myshash field -1 # 执行一次,值+9 (integer) 6 127.0.0.1:6379> hincrby myshash field 9 # 执行一次,值+9 (integer) 15 127.0.0.1:6379> hsetnx myshash firld1 hello # 如果不存在则创建赋值 (integer) 1 127.0.0.1:6379> hsetnx myshash firld1 he # 如果存在则返回0 (integer) 0list实际上是个双向链表,但是可以完成栈和队列
消息队列(lpush rpop) 栈(lpush lpop)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
# 大部分的list命令都是以L开头的 ####################################################################################### 127.0.0.1:6379> Lpush list one two # 将一个或者多个值插入到列表的头部,以栈的形式 (integer) 2 127.0.0.1:6379> keys * 1) "user:1" 2) "list" 3) "user:2:age" 4) "user:2:name" 5) "db" 127.0.0.1:6379> Lpop list # 弹栈 "two" 127.0.0.1:6379> lpop list # 弹栈 "one" 127.0.0.1:6379> lpop list # 弹栈 (nil) 127.0.0.1:6379> keys * 1) "user:1" 2) "user:2:age" 3) "user:2:name" 4) "db" 127.0.0.1:6379> Lpush list one two (integer) 2 127.0.0.1:6379> Lrange list 0 -1 # 查看所有压入的值 1) "two" 2) "one" 127.0.0.1:6379> ####################################################################################### # 在现有的列表中插入值 查出 删除 127.0.0.1:6379> Lrange list 0 -1 1) "two" 2) "one" 127.0.0.1:6379> lpush list three # 相当于在栈顶压入值 (integer) 3 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "two" 3) "one" 127.0.0.1:6379> Rpush list for # 相当于在队头插入值 (integer) 4 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "two" 3) "one" 4) "for" 127.0.0.1:6379> lindex list 1 # 根据下标查出值 下标从0开始 "two" 127.0.0.1:6379> lindex list 0 "three" 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "two" 3) "one" 127.0.0.1:6379> lrem list 1 two # 删除值 (integer) 1 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "one" ######################################################################################## # ltrim 修剪 127.0.0.1:6379> lrange list 0 -1 1) "one" 2) "for" 3) "two" 4) "three" 127.0.0.1:6379> ltrim list 1 2 # 修剪list的下标为1和2的 只剩下1和2 OK 127.0.0.1:6379> lrange list 0 -1 1) "for" 2) "two" 127.0.0.1:6379> ####################################################################################### # 在指定的位置插入值 linsert 127.0.0.1:6379> lrange list 0 -1 1) "zsy" 2) "cc" 3) "wsx" 127.0.0.1:6379> linsert list before cc love # 在cc的前面加个love (integer) 4 127.0.0.1:6379> lrange list 0 -1 1) "zsy" 2) "love" 3) "cc" 4) "wsx" 127.0.0.1:6379> linsert list after cc 1130 # 在cc的后面加个1130 (integer) 5 127.0.0.1:6379> lrange list 0 -1 1) "zsy" 2) "love" 3) "cc" 4) "1130" 5) "wsx" 127.0.0.1:6379>set中的值是不能重复的
Redis的Set是string类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
用例:
微博,a用户的所有关注的人放在一个set集合中!将它的粉丝也放在一个集合中!共同关注。共同爱好,二度好友,推荐好友!(六度分割理论)
127.0.0.1:6379> sadd myset hello xjp lovecc # 添加元素到myset集合中 (integer) 3 127.0.0.1:6379> smembers myset # 遍历 1) "xjp" 2) "hello" 3) "lovecc" 127.0.0.1:6379> sismember myset xjp # 查询集合中是否存在该元素 (integer) 1 127.0.0.1:6379> sismember myset zsy (integer) 0 127.0.0.1:6379> scard myset # 查询集合的总长度 (integer) 3 127.0.0.1:6379> srem myset hello # 删除该集合中的hello元素 (integer) 1 127.0.0.1:6379> smembers myset 1) "xjp" 2) "lovecc" 127.0.0.1:6379> srandmember myset # 随机查出一个值 "lovecc" 127.0.0.1:6379> srandmember myset "xjp" 127.0.0.1:6379> spop myset # 随机弹出一个值 "lovecc" 127.0.0.1:6379> smembers myset 1) "xjp" ######################################################################################### 127.0.0.1:6379> sadd myset abd def ghi jkl mn (integer) 5 127.0.0.1:6379> smembers myset 1) "abd" 2) "def" 3) "jkl" 4) "ghi" 5) "mn" 127.0.0.1:6379> smove myset myset1 jkl # 将一个指定的值移到另一个set集合中 (integer) 1 127.0.0.1:6379> smembers myset1 1) "jkl" 127.0.0.1:6379> smembers myset 1) "def" 2) "ghi" 3) "mn" 4) "abd" ######################################################################################### 数字集合类: - 差集 sdiff - 交集 sinter - 并集 sunion 127.0.0.1:6379> sadd myset a b c d e f g (integer) 7 127.0.0.1:6379> sadd myset1 a b c d (integer) 4 127.0.0.1:6379> sdiff myset myset1 # 差集 1) "f" 2) "g" 3) "e" 127.0.0.1:6379> sinter myset myset1 # 交集 1) "c" 2) "b" 3) "d" 4) "a" 127.0.0.1:6379> sunion myset myset1 # 并集 1) "g" 2) "b" 3) "c" 4) "a" 5) "e" 6) "d" 7) "f" 127.0.0.1:6379>Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
127.0.0.1:6379> zadd myset 1 xjp 2 zk 3 zsy # 创建个有序集合,1,2相当于代表下标 (integer) 3 127.0.0.1:6379> zrange myset 0 -1 #遍历 1) "xjp" 2) "zk" 3) "zsy" 127.0.0.1:6379> zadd salary 2500 xiaohong 5000 zhangsan 500 kuangsen (integer) 3 127.0.0.1:6379> 127.0.0.1:6379> zrangebyscore salary -inf +inf # 排序 相当于从负无穷到正无穷进行排序 1) "kuangsen" 2) "xiaohong" 3) "zhangsan" 127.0.0.1:6379> zrangebyscore salary -inf +inf withscores # 排序 并将下标一起显示 1) "kuangsen" 2) "500" 3) "xiaohong" 4) "2500" 5) "zhangsan" 6) "5000" 127.0.0.1:6379> zrangebyscore salary -inf 2500 withscores # 取负无穷到2500之间的值 1) "kuangsen" 2) "500" 3) "xiaohong" 4) "2500" 127.0.0.1:6379> zrevrange salary 0 -1 # 逆序 1) "zhangsan" 2) "xiaohong" 3) "kuangsen" 127.0.0.1:6379> zcard salary # 查看该集合中有多少个值 (integer) 3 127.0.0.1:6379> zcard myset (integer) 3 127.0.0.1:6379> zcount myset 0 1 # 查询0到1这个范围类有多少个值 (integer) 1 127.0.0.1:6379>底层是zset zset的所有命令都适用
127.0.0.1:6379> geoadd china:city 116.16 40.05 beijing # 添加位置 经度 纬度 城市 (integer) 1 127.0.0.1:6379> geoadd china:city 121.48 31.10 shanghai 113.88 22.55 shenzhen 113.27 23.15 guangzhou (integer) 3 127.0.0.1:6379> geoadd china:city 120.21 30.20 hangzhou 114.02 30.58 wuhan 112.89 30.40 qianjiang (integer) 3 127.0.0.1:6379> geopos china:city hangzhou # 查看城市的经度 纬度 1) 1) "120.21000176668167114" 2) "30.19999988833350102" 127.0.0.1:6379> geopos china:city hangzhou beijing 1) 1) "120.21000176668167114" 2) "30.19999988833350102" 2) 1) "116.1600002646446228" 2) "40.04999982043828055" 127.0.0.1:6379> geodist china:city beijing wuhan # 查看两个城市之间的距离 "1070968.9641" 127.0.0.1:6379> geodist china:city beijing wuhan km "1070.9690" 127.0.0.1:6379> georadius china:city 100 20 10000 km # 查看以经度100 纬度20为中心半径为10000km的城市 1) "shenzhen" 2) "guangzhou" 3) "qianjiang" 4) "wuhan" 5) "hangzhou" 6) "shanghai" 7) "beijing" 127.0.0.1:6379> GEORADIUSBYMEMBER china:city wuhan 1000 km # 以某个城市为中心画圆 1) "shenzhen" 2) "guangzhou" 3) "qianjiang" 4) "wuhan" 5) "hangzhou" 6) "shanghai" 127.0.0.1:6379>一般用来统计访问量,基数
例如:同一个用户的访问网站,网站只能加1
127.0.0.1:6379> pfadd mykey a b c d e f g h # 添加 (integer) 1 127.0.0.1:6379> pfcount mykey # 显示无重复的个数 (integer) 8 127.0.0.1:6379> pfadd mykey1 q qe r g d a s b (integer) 1 127.0.0.1:6379> pfcount mykey1 (integer) 8 127.0.0.1:6379> PFMERGE mykey2 mykey mykey1 #合并 取并集 OK 127.0.0.1:6379> pfcount mykey2 (integer) 12 127.0.0.1:6379>统计是否打卡,活跃用户,不活跃用户,登陆用户 未登录用户等
bitmaps位图,数据结构! 都是操作二进制来进行记录。只有0和1两个状态,占内存特别少
127.0.0.1:6379> setbit bit 0 0 # 模拟每周打卡 (integer) 0 127.0.0.1:6379> setbit bit 1 0 (integer) 0 127.0.0.1:6379> setbit bit 2 1 (integer) 0 127.0.0.1:6379> setbit bit 3 1 (integer) 0 127.0.0.1:6379> setbit bit 4 1 (integer) 0 127.0.0.1:6379> setbit bit 5 0 (integer) 0 127.0.0.1:6379> setbit bit 6 1 (integer) 0 127.0.0.1:6379> getbit bit 6 # 查看周六有没有打卡 (integer) 1 127.0.0.1:6379> getbit bit 5 # 查看周五有没有打卡 (integer) 0 127.0.0.1:6379> bitcount bit # 查看总打卡天数 (integer) 4redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,都会按顺序执行
一次性,顺序性,排他性!执行一些列的命令!
redis事务没有隔离级别的概念
Redis单条命令式保存原子性的,但是redis事务不保证原子性
事务每执行完成后 该事务就没了,需要重新开启事务
redis的事务:
开启事务(multi)命令入队(…)执行事务(exec) 127.0.0.1:6379> multi # 开启事务 OK # 命令入队 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> get k1 QUEUED 127.0.0.1:6379> exec # 执行事务 1) OK 2) OK 3) "v1" 127.0.0.1:6379>可以一次执行多个命令,本质是一组命令的集合。
一个事务中的所有命令都会序列化,按照顺序地串行化执行而不会被其他命令插入,不许加塞
一个队列中,一次性、顺序性、排他性的执行一系列命令
Redis中开启事务的命令是:MULTI ,这个命令通常会回复一个OK【回复的是OK,但是这个事能不能办,什么时候办,办不办的成不知道】,用户将会一次性的打多个命令,而代替执行,按顺序执行,Redis将这些命令入队,所有的命令将会通过命令:EXEC 来被调用执行。
如果用命令:DISCARD 表示放弃丢弃,言下之意是放弃本次的批处理操作
DISCARD:取消事务,放弃执行事务块内的所有命令
EXEC:执行所有事务块内的命令
MULTI:标记一个事务块的开始
UNWATCH:取消 WATCH 命令对所有 key 的监控
WATCH key [key . . . ]:件事一个(或多个)key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断
悲观锁
悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,当其他线程想要访问数据时,都需要阻塞挂起。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁、表锁,读锁,写锁等,都是在操作之前先上锁。
在Java中,synchronized的思想也是悲观锁。
乐观锁:【冲突检测和数据更新】
乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候回判断一下再次期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。
乐观锁策略:提交版本必须大于记录当前版本才能执行更新
一般会使用版本号机制或CAS操作实现:
version方式:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。
核心SQL代码:
update table set x=x+1, version=version+1 where id=#{id} and version=#{version};
CAS(Check And Set【先检查再动手设置】)
CAS操作方式:即 compare and set,CAS是乐观锁技术,涉及到三个操作数,数据所在的内存值,预期值,新值。当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。
如下图:就模拟了一个购物的过程,在买的过程中,别人会给你打钱,当你要完成支付的时候报错了
解决:【使用 UNWATCH 取消对当前 key 的监控,之后再一次进行监控(得到最新的数据),直到成功为止】
通过 WATCH 命令在事务执行之前监控了多个 Keys,倘若在 WATCH 之后有任何 Key 的值发生变化,EXEC 命令执行的事务都将被放弃,同时返回 Nullmulti-bulk 应答以通知调用者事务执行失败
开启:以 MULTI 开始一个事务
入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
执行:由 EXEC 命令触发事务
单独的隔离操作:事务中所有的命令多会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际的执行,也就是不存在 “ 事务内的查询要看到事务里面的更新,在事务外查询不能看到 ” 这个是让人万分头痛的问题
不保证原子性:Redis 同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
什么是jedis?是redis官方推荐的java连接开发工具,使用java操作redis中间件!
由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF持久化(原理是将Reids的操作日志以追加的方式写入文件)。
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
rdb:
优点:适合大规模的数据恢复
对数据的完整性要求不高
缺点:需要一定的时间间隔进程操作!如果redis意外宕机了,这个最后一次修改的数据就丢失了
fork子进程的时候,会占用一定的内存空间
aof:
优点:AOF可以更好的保护数据不丢失。 一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作, 最多丢失1秒钟的数据,Redis进程挂了,最多丢掉1秒钟的数据;
每一次修改都同步 文件的完整性比较好
AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。每一次进行aof持久化都会写入,当文件越来越大大于64m时,则会创建新的日志文件;
缺点 :相对于数据文件来说,aof远远大于rdb,修复速度也比rdb慢
aof的运行效率也比rdb慢,redis默认支持的是rdb 持久化
订阅端
127.0.0.1:6379> subscribe dmxu # 订阅了一个频道dmxu Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "dmxu" 3) (integer) 1 # 等待读取推送的信息 1) "message" # 消息 2) "dmxu" # 频道 3) "successxu" # 消息的具体内容 1) "message" 2) "dmxu" 3) "jiayou" 1) "message" 2) "dmxu" 3) "qifei"发送端
127.0.0.1:6379> publish dmxu successxu # 发送消息到频道 (integer) 1 127.0.0.1:6379> publish dmxu jiayou (integer) 1 127.0.0.1:6379> publish dmxu qifei (integer) 1 127.0.0.1:6379>只配置从库,不用配置主库
127.0.0.1:6379> info replication # 查看当前库的信息 # Replication role:master # 角色 master connected_slaves:0 # 没有从机 master_replid:3c89d46ff34efb6cc1586b724a41008b864f4397 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:0 second_repl_offset:-1 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0 127.0.0.1:6379>复制3个配置文件,然后修改对应的信息
端口后台运行 daemonize yespidfile 名字log文件名字dump.rdb名字默认情况下,每台redis服务器都是主节点一般情况下只用配置从机
认老大! 一主(79)二从(80,81)
######################################################################################### #主机 6379 127.0.0.1:6379> info replication # Replication role:master connected_slaves:2 # 多了两个从机的配置 slave0:ip=127.0.0.1,port=6380,state=online,offset=1316,lag=0 slave1:ip=127.0.0.1,port=6381,state=online,offset=1316,lag=0 master_replid:185e074eb80a6ec61f60a428023b9671f39e1159 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:1316 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:1316 127.0.0.1:6379> ######################################################################################### # 从机6380 127.0.0.1:6380> slaveof 127.0.0.1 6379 # 认6379为老大 OK 127.0.0.1:6380> info replication # Replication role:slave # 角色 从机 master_host:127.0.0.1 # 主机的信息 master_port:6379 master_link_status:up master_last_io_seconds_ago:2 master_sync_in_progress:0 slave_repl_offset:1302 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:185e074eb80a6ec61f60a428023b9671f39e1159 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:1302 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:1302 127.0.0.1:6380> ######################################################################################### # 从机6381 127.0.0.1:6381> slaveof 127.0.0.1 6379 #认6379为老大 OK 127.0.0.1:6381> info replication # Replication role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:5 master_sync_in_progress:0 slave_repl_offset:1274 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:185e074eb80a6ec61f60a428023b9671f39e1159 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:1274 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1261 repl_backlog_histlen:14 127.0.0.1:6381>真实的主从配置是在配置文件中配置 是永久的,命令中配置是暂时的
主机可以写,从机不能写只能读!主机中的所有信息和数据,都会自动被从机保存
主机:
从机:
测试:如果主机断开连接,从机依旧连接到主机,也可以读到主机之前写入的值;此时主机如果回来了,从机依然可以获得主机写的信息
如果从机断开连接,再回来;如果使用的是命令行配置,则回来后默认变成主机,不能读取之前主机上的任何操作,需要将其变成从机,从而可以继续读取主机上的信息
哨兵模式是主从复制的一种优化形式;当主机宕机后,哨兵会在剩下的从机中投票选出一个主机,当原有的主机重新恢复后,原有的主机则变成现有主机的从机
1.配置配置文件
创建多个sentinel.conf 配置集群 例如sentinel79.conf sentinel80.conf
port 26379 # sentinel monitor是命令 mymast是名称 随机取的 sentinel monitor mymast 127.0.0.1 6379 1 #主节点 名称 IP 端口号 选举次数 logfile "/usr/local/bin/xuconfig/sentinel.log.26379" port 26379 # sentinel monitor是命令 mymast是名称 随机取的 sentinel monitor mymast 127.0.0.1 6380 1 #主节点 名称 IP 端口号 选举次数 logfile "/usr/local/bin/xuconfig/sentinel.log.26380"2.启动sentinel.conf
[root@localhost bin]# redis-sentinel xuconfig/sentinel79.conf & [1] 6241 [root@localhost bin]# redis-sentinel xuconfig/sentinel80.conf & [2] 6245