Redis学习心得

Redis学习笔记

第一节 安装运行redis

1.linux下安装redis,系统

wget http://download.redis.io/releases/redis-6.0.5.tar.gz   //下载redis指定版本的源码压缩包到当前目录
tar xzf redis-6.0.5.tar.gz	-C /usr/local					//解压文件到	/usr/local	文件夹下
cd /usr/local/redis-6.0.5									//进入到redis-6.0.5目录
ln -s redis-6.0.5 redis										//建立一个redis目录的软连接,指向redis-6.0.5
cd redis													//进入redis目录
make														//编译(编译之前确保环境已安装gcc)
make install												//安装
vim redis.conf												//修改下面配置
1、注释掉bind 允许所有ip连接redis
# bind 0.0.0.0 

2、注释redis保护模式
# protected-mode yes

3、设置reids密码
requirepass 123456 

2.运行redis
默认配置启动

redis-server

运行参数启动
redis-server --configKey1 configValue1 --configKey2 configValue2
例如

redis-server --port 6380

运行配置文件启动(建议,这是后台启动)例如我

redis-server {path}/redis.conf   //我的配置文件在/usr/local/redis/redis文件下 把path替换掉

3.运行命令行客户端

redis-cli -h {ip} -p{port} //如不填-h{ip}和-p{port} 则默认启动本地6379端口

4.停止redis服务
查看redis是否在运行:

 ps aux | grep redis

如果是通过源码安装的redis,则可以通过redis的客户端程序redis-cli的shutdown命令来重启redis

启动redis:

redis-server redis.conf

关闭redis:

redis-cli shutdown

当设置密码后,上面的关闭命令无效:带密码输入: redis-cli -a [password] 回车后输入:shutdown

即可关闭redis,输入exit 退出

查看redis密码;可查看 redis 安装根目录下的配置文件:redis-conf 中SECURITY下面的 requirepass 后面的内容

如果上述方式都没有成功停止redis,则可以使用终极武器 kill -9

第二节redis命令

redis全局命令

1.keys *   //*代表模糊查询,可以带关键字。例如:keys my*  将查询到my开头的所有键。
2.dbsize  //查询有多少个键。
3.exists key //检查键是否存在
4.del keys...  //删除键,可以输入多个,以空格分割。例如del a b c 
5-1.expire key seconds //设置键过期时间,seconds代表整数(如果是负数,key将删除,等于del key),单位秒。例如:expire mylist 1000  //如果键不存在返回0,存在返回1
5-2.pexpire key milliseconds //设置键过期时间,milliseconds代表整数(如果是负数,key将删除,等于del key),单位毫秒。例如:pexpire mylist 1000  //如果键不存在返回0,存在返回1
5-3.expireat key timestamp //设置键过期时间,timestamp代表时间戳(如果时间戳小于当前时间,key将删除,等于del key),例如:expireat mylist 1718311918071  //如果键不存在返回0,存在返回1 
5-4.pexpireat key millitimestamp //设置键过期时间,millitimestamp代表毫秒级时间戳(如果时间戳小于当前时间,key将删除,等于del key)。例如:pexpireat mylist 1718311918071   //如果键不存在返回0,存在返回1
6.ttl key   //查询过期时间,如果没有设置过期时间返回 -1,如果键不存在返回-2。
7.type key  //键类型,如果键不存在返回 none
8.incr key  //自增1,如果键不存在,则新增键。
9.object encoding key //查询键内部编码,例如String类型的数据,包含raw,int,embstr 三种类型
10.rename key newkey  //键重命名,如果newkey已经存在,那么旧的value将被覆盖。
11.renamenx key newkey //键重命名,如果newkey已经存在,返回0,表示失败,保持原样。
12.randomkey			//随机获取一个key
13.persist key          //清除设置的过期周期。

迁移键

14.move key db 			//redis可以有多数据库,从source database  迁移到 target database (不建议使用)
15.dump key  			//源数据库上备份key,把value序列化 (不建议使用)
16.restore key 0 "序列化字符串" //在目标数据库上执行,默认是0号数据库,可以不写(不建议使用)
17.migrate targethostip  targethostport key|"" target-db timeout [copy] [replace] [auth password] [keys key1 key2 ...]//如果迁移一个键,就是key,多个键就填"", target-db是目标的数据库号,一般都是0,timeout 迁移超时时间,copy 迁移后不删除源,replace 覆盖目标中相同的键,如果目标有密码保护需要带上auth password 例如:migrate localhost 6380 "" 0 5000 copy replace auth 123456  keys age1 age2 age3 age4 age5 age6

清除及遍历

18.redis-cli [-a password] keys * | xargs redis-cli [-a password] del     //需要在退出状态才可以执行,有可能阻塞。
19.flushdb    			//清空当前数据库中所有key
20.flushall 			//清空服务器所有数据库0-15的数据
21-1.scan cursor [match pattern] [count number]		//模糊匹配遍历所有键,pattern 模糊匹配,number 键的数量。
21-2.hscan cursor [match pattern] [count number]	//模糊匹配遍历指定哈希键的value。pattern 模糊匹配,number value的数量。
21-3.sscan cursor [match pattern] [count number]	//模糊匹配遍历指定集合键的value。pattern 模糊匹配,number value的数量。
21-4.zscan cursor [match pattern] [count number]//模糊匹配遍历指定有序集合键的valuepattern,模糊匹配,number value的数量。
22.select index        	//切换数据库默认有0到15,共16个数据库

redis是单线程架构,为何还那么快?
1.纯内存访问
2.非阻塞I/O
3.单线程避免了线程切换和竞态产生的消耗。

数据类型及命令

String

常用命令

1.set key value [ex seconds] [px milliseconds] [nx|xx] //设置秒级,毫秒级过期值,nx 表示键不存在才可以设置成功,xx 表示键必须存在才可以设置成功。
2-1.setex key seconds value 	//这是上面的变种命令
2-2.setnx key value 		//nx 表示键不存在才可以设置成功,xx 表示键必须存在才能设置, 使用场景为分布式锁的一种实现方案
3.get key   				//获取值,如果不存在返回nil 
4.mset key1 value2 key2 value2 ...    //批量设置键值对。
5.mget key1 key2 key3 ...	// 批量获取值。
6.incr key  				//自增1,如果键不存在,则新增键。如果value不是整数的返回错误
7.decr key  				//自减1,
8.incrby key increment 		//增加increment值
9.decrby key decrement 		//减去decrement值
10.incrbyfloat key increment//增加increment值(浮点数)

不常用命令

11.append key value //追加值,,在原来的值后面追加value值
12.strlen key   		//获取字符串长度,中文占3个字节
13.getset key value   //设置新值,返回旧值。
14.setrange key offeset value   //修改指定位置的字节为新值 例如:a=123542, setrange a 1 434 ,设置key为a的值左边第一个字节开始共3个字节为434. a=143442
15.getrange key start end  //获取指定位置的字符串,从左边开始,0是第一位。

位操作

16-1.setbit key index 0|1		//字符串在内存上是以字节,位来存储的,所以可以以位的方式来操作和查看.
16-2.getbit key index 			//查看指定位的值。
16-3.bitcount key 				//统计有多少位为1. 该模式可以用来记录值为正反,男女的数据。
16-4.bitop and|or|not|xor newkey  key1 key2 // 对key1 和key2 的value值做位运算。
16-5.bitpos key 0|1 start end	//查找从start到end间,第一个为0|1的位索引。

HyperLogLog 操作

17-1.pfadd key element1 element2 ...	//像操作set一样来使用String ,有一定的错误率,可以用来做不要求很精准的统计使用,内存占用少。
17-2.pfcount key 						//统计有多少个element。
17-3.pfmerge newkey key1 key2 			//合并key1 key2 ,存储到newkey 中

备注:raw(大于39字节),int(8字节),embstr(小于等于39字节) 三种类型,

应用场景
缓存
伪代码如下:

UserInfo getUserInfo (long id)
{
	userRedisKey = "user:info:"+id;
	value = redis.get(userRedisKey);
	UserInfo userInfo;
	if(value!=null)
	{
		//反序列化字符串为对象
		userInfo = deserialize(value);
	}else
	{
		userInfo = mysql.get(id);
		if(userInfo!=null)
		{
			//序列化对象为字符串缓存起来
			redis.setex(userRedisKey,3600,serialize(userInfo));
		}
	}
	return userInfo;
}

计数器 例如视频播放计数
伪代码如下:

long incrVideoCounter(long id)
{
	String key = "video:playCount:"+id;
	return redis.incr(key);
}

分布式系统session共享
用户登录后把session对象存入redis,下次访问如果路由到其他服务器时,可以通过从redis获取用户session,获得用户登录信息,防止再次登录。

限速 例如限制获取手机验证码的周期
伪代码如下:

String phoneNum = "13811112222";
String key = "shortMsg:limit:"+phoneNum;
//set key value ex 60 nx
int isExists = redis.set(key,1,"ex 60","nx");
if(isExists !=null || redis.incr(key) <=1){
	//通过
}else{
	//限速
}

哈希(常用命令)

结构对比:

key	                value
user:1:name			tom						String
user:1:age			28						String
user:1				{name:tom;age:28}		哈希

哈希类型中映射关系叫做field-value,注意value是指field对应的值。

1.hset key field value 							//设置值 例如hset user:1 name 'li kai' age 78
2.hget key field       							//获取值 例如hget user:1 name   如果field不存在就返回nil,如果key不存在就返回error
3.hdel key field1 field2 field3       			//删除值 例如hdel user:1 age    返回成功删除的个数。
4.hlen key 										//计算field的个数   例如hlen user:1   
5.hmset key field1 value1 field2 value2 ...   	//批量设置值
6.hmget key field1 field2 ...					//批量获取field值
7.hexists key field 							//判断是否存在某个field   例如 hexists user:1 age 存在返回1,不存在返回0
8.hkeys key             						//获取所有的field  例如hkeys user:1   返回字符串数组
9.hvals key 									//获取所有的value  例如hvals user:1   返回字符串数组
10.hgetall key 									//获取所有的field和value  例如hgetall user:1 建议使用hmget获取多个field的value,防止阻塞。
11.hincrby key field increment  				//自增某个field的值,与String的incr一样,但是必须带上increment 例如hincrby user:1 age 1
12.hincrbyfloat key field increment				//自增某个field的值(float),与String的incr一样,但是必须带上increment 例如hincrbyfloat user:1 age 20.23
13.hstrlen key field    						//计算某个field的value值长度。 例如:hstrlen user:1 name

编码备注:
ziplist(压缩列表):field少于512个,value值都小于64字节、
hashtable(哈希表):比ziplist读写快,但是需要内存大于ziplist

使用场景
缓存
伪代码如下:

UserInfo getUserInfo (long id)
{
	//用户id作为key的后缀
	userRedisKey = "user:info:"+id;
	//使用hgetall获取用户id对应的用户信息
	Map usermap = redis.hgetall(userRedisKey);
	UserInfo userInfo;
	if(usermap!=null)
	{
		userInfo = transferMapToUserInfo(usermap);
	}else
	{
		//从mysql中获取用户信息
		userInfo = mysql.get(id);
		if(userInfo!=null)
		{
			redis.hmset(userRedisKey,transferUserInfoToMap(userInfo));
			redis.expire(userRedisKey,3600);
		}
	}
	return userInfo;
}

列表(常用命令)

添加:

1.rpush key value1 value2 ...  			//从右添加,也可以说从尾部添加。例如: rpush mylist 1 2 3 4   --[1,2,3,4]
2.lpush key value1 value2 ...  			//从左添加,也可以说从头部添加。例如: lpush mylist 5 6 7 8   --[8,7,6,5,1,2,3,4]
3.linsert key before|after element value	//从某个element前或后插入元素value。例如 linsert mylist before 5 89  --[8,7,6,89,5,1,2,3,4]

查找:

4.lrange key start end 	//下标范围查找,start和end可以从左数(0到n-1),也可以从右数(-1到-n)例如:lrange mylist 2 -2  --[6,89,5,1,2,3]
5.lindex key index		//下标准确查找,index也可以从左数(0到n-1),也可以从右数(-1到-n)例如:index key -2  --3
6.llen key 				//获取列表长度,例如 llen mylist 

删除:

7.lpop key 				//从左弹出元素,也可以说从头部弹出元素,
8.rpop key 				//从左弹出元素,也可以说从头部弹出元素,
9.lrem key count element  //count如果是正数,从左边开始删除count个value=element的元素,count如果是负数从右边开始删除|count|个value=element的元素,为0删除所有value=element的元素
10.ltrim key start end  	//保留start到end的元素,其余的删除。start和end可以从左数(0到n-1),也可以从右数(-1到-n)例如:ltrim mylist 2 -2

修改:

11.lset key index newValue  //修改指定下标的元素为newValue

阻塞:

12.blpop|brpop key1 key2 ...  timeout  //timeout单位为秒,如果timeout为0,而list没有元素可以弹出则一直等下去,如果timeout不为0,时间到则返回nil,可以输入多个key,只有有元素返回则直接返回

编码备注:
ziplist(压缩列表):element少于512个,长度都小于64字节、
linkedlist(链表):比ziplist读写快,但是需要内存大于ziplist
quicklist(快速列表):是ziplist与linkedlist的结合。3.2版本后才有

使用场景
消息队列

生产着 -> lpush key  -> redis ->  brpop -> 消费着

开发提示:

lpush + lpop = stack (栈)
lpush + rpop = Queue  (队列)
lpush + ltrim = Capped Collection (有限集合)
lpush + brpop = Message Queue (消息队列)

缓存一对多关系数据,假如用户有多个角色,
哈希缓存角色信息,list缓存的key设置为用户+id,value 可以存储角色id

集合(常用命令)

特点:不允许元素重复,无序的,所以不能通过下标获取元素。
操作单集合:

1.sadd key element1 element2 ...   	//添加元素,返回添加成功的个数
2.srem key element1 element2 ...	//删除元素,返回删除成功的个数
3.scard key 						//计算元素个数
4.sismember key element				//判断元素是否存在
5.srandmember key [count]			//随机获取count个元素,不输入count则默认一个
6.spop key [count]  				//随机弹出count个元素,不输入count则默认一个
7.smembers key 						//获取所有元素,该命令与lrange,hgetall 都是比较长时间的命令,可能阻塞。

集合间操作:

8.sinter key1 key2 ...				//取多个集合的交集
9.sunion key1 key2 ...				//取多个集合的并集
10.sdiff key1 key2 ...				//取多个集合的差集
11.sinterstore destination key1 key2 ... //取多个集合的交集并保存在distination中

编码备注:
intset(整数集合):element少于512个,都是整数。
hashtable(哈希表):不满足inset条件时

使用场景
1.比如每个人都有多种兴趣爱好,可以通过集合找出相同爱好的人,获取找出这些人的共同爱好。
可以以用户做为key,也可以以爱好做为key。实现不同的查找需求
例如:添加用户及爱好时,
第一步给用户添加标签

sadd users:user1 tag1 tag2 tag3 tag6
sadd users:user2 tag1 tag4 tag5 tag6
sadd users:user3 tag2 tag3 tag6

第二步同时给标签添加用户

sadd tags:tag1 user1 user2
sadd tags:tag2 user1 user3
sadd tags:tag3 user1 user3
sadd tags:tag4 user2
sadd tags:tag5 user2
sadd tags:tag6 user1 user2 user3

这两步需要在一个事务中执行。

第三步删除某个用户爱好时

srem users:user1 tag1 tag3

第四步同时修改爱好标签集合

srem tags:tag1 user1
srem tags:tag3 user1

这两步也需要在一个事务中执行。

计算用户的共同爱好

sinter users:user1 users:user2 

2.比如公司抽奖,把员工名字或者工号放入一个集合中,随机弹出100个元素作为6等奖,

spop nameset 100

有序集合(常用命令)

特点:不允许元素重复,有序的,所以不能通过下标获取元素。但是有一个分数score伴随着element用于排序和条件查询,score是可以重复的
操作单集合:

1.zadd key score1 member1 score2 member2 ...   	//添加元素,返回添加成功的个数
2.zadd key [nx|xx] [incr] score member   		//当输入nx时,表示元素不存在新增,如果输入xx表示元素存在,可以修改其分数,也可
以输入incr 和分数,表示在原来的分数上加上该分数。
3.zcard key 									//计算元素个数
4.zscore key member  							//返回某个元素的分数,如元素不存在则返回nil
5.zrank key member								//计算某个成员的分数从低到高排名,从0开始排序
6.zrevrank key member 							//计算某个成员的分数从高到低排名,从0开始排序
7.zrem key member1 member2 ...					//删除多个元素,返回成功删除的个数
8.zincrby key increment member					//增加某个元素的分数,如果元素不存在则新增元素,score=increment
9.zrange key start end [withscores]				//获取排位(从低到高排序)在start到end的元素,start从0开始。end可以是负数,表示倒数,带withscores参数则返回值带分数
10.zrevrange key start end 	[withscores]		//获取排位(从高到低排序)在start到end的元素,start从0开始。带withscores参数则返回值带分数
11.zrangebyscore key min max [withscores] [limit start count]  //获取区间分数的元素,start从0开始,count 返回多少个。
12.zrangebyscore key (min (max [withscores] [limit start count]  //获取区间分数的元素(不包含等于min的元素和等于max的元素),start从0开始,count 返回多少个。
13.zrangebyscore key -inf +inf [withscores] [limit start count] //获取无限小到无限大分数的元素
14.zcount key min max 							//获取区间分数的元素个数,也可以带小括号,无限小,无限大等参数。
15.zremrangebyrank key start end 				//删除排位(从低到高排序)在start到end的元素,start从0开始。
16.zremrangebyscore key min max 				//删除区间分数的元素,min,max也可以带小括号,无限小,无限大等参数。

集合间操作:

17.zinterstore newkey n key1 key2 ... keyn [weights weight1 weight2 ... weightn] [aggeregate sum|min|max] //取交集,中括号的值是对相同元素的score的计算,weight*score 后再进行sum|min|max运算
18.zunionstore newkey n key1 key2 ... keyn [weights weight1 weight2 ... weightn] [aggeregate sum|min|max] //取并集,中括号的值是对相同元素的score的计算,weight*score 后再进行sum|min|max运算

GEO地理位置底层是zset。

1.geoadd key longitude latitide member1 longitude latitide member2 ...		//longitude 经度,latitide 纬度,member1 地名
2.geopos key member1 //	查看key中member1成员的经纬度
3.geodist key member1 member2 [unit]  //获取两地的距离unit 可以是m 米,km 千米,mi 英里,ft 尺
4-1.georadius key longitude latitide  rkm|m|mi|ft [withcoord] [withdist] [withhash] [COUNT n] [asc|desc] [store newkey1] [storedist newkey2] 
//计算离中心经纬度r距离为半径的成员,withcoord:结果带经纬度 withdist:结果带距离 withhash:结果带geohash  COUNT n 指定返回n个,asc|desc 按距离升降序返回,store newkey1  经纬度hash值存储在newkey1 type 是zset,storedist newkey2 距离存储在newkey2 ,type 是zset。结果只能返回一种,不可都写,如果需要储存则不用写带结果返回,也只能存储一种。
4-2.georadiusbymember key member  rkm|m|mi|ft [withcoord] [withdist] [withhash] [COUNT n] [asc|desc] [store newkey1] [storedist newkey2] 
5.geohash key member1 member2 ...		//获取成员经纬度的hash值
6.zrem key member						//删除成员信息

编码备注:
ziplist(压缩列表) 元素小于128个,元素值都小于64kb
skiplist(跳跃表)当条件不满足ziplist时

发布订阅

1.publish channel message   //向频道发布消息
2.subscribe channel1 channel2 ....  //向多个频道订阅
3.psubscribe pattern1 pattern2 ...  //向多个模糊匹配的频道订阅

慢查询分析

1.slowlog-log-slower-than=10000 		//慢查询默认值10000微秒,也就是10毫秒。当超过该阀值时,会记录日志
2.slowlog-log-slower-than=0 			//会记录所有命令的日志
3.slowlog-log-slower-than<0				//不会记录日志
4.slowlog-max-len=1000					//记录保持多少条,当超过阀值时,把旧纪录删除。
5-1.config set slowlog-log-slower-than 0 	//可以通过修改配置
5-2.config rewrite							//修改的配置保存到文件
6.slowlog get [n] 						//获取慢查询日志,n 代表获取多少条,默认返回最近的n条,不写n,返回所有。
7.slowlog len							//获取慢查询日志统计数
8.slowlog reset							//清空慢查询日志。

脚本

Redis shell

1-1.redis-cli [-r n subcommand]	//执行n次子命令。 
1-2.redis-cli [-r n -i m subcommand]	//执行n次子命令。每隔m秒执行一次
1-3.echo "world" | redis-cli -x set hello //从标准输出获取值作为value值。
1-4.redis-cli --slave 					//获取当前redis实例的更新操作。
1-5.redis-cli --rdb 					//生成备份文件RDB文件保存到本地

事务

1.multi 和exec  两个命令之间执行的更新操作将同一时间被执行。当有异常发生时回滚。
2.watch ,multi,exec //带锁的事务,当watch 监控的key发生了改变时,multi,exec 之间的命令事务回滚。

Lua 脚本

1.eval 'script' numkeys key1 key2 ... arg1 arg2 ...	//执行lua脚本
2.script load 'script'								//加载lua脚本
3.script exists sha1 sha2 ... 						//判断脚本是否已加载
4.script flush										//清除已加载的lua脚本
5.script kill 										//杀掉正在阻塞的lua脚

Redis 哨兵与集群配置(以下方法都测试过)

如果采用哨兵模式,需要对redis做哨兵部署。

1.主从配置:

主机配置如文章开头一样
从机配置需要复制主机redis.conf 文件后重命名如 redis6380.conf,redis6381.conf并增加如下配置对应自己的端口号

replicaof 192.168.10.2  6379    #192.168.10.2 是主机地址  6379是主机端口 #旧版是slaveof 
masterauth 123456				#123456 是主机密码
port 6380		#6380是从机自己的端口号,6381是从机自己的端口号,

启动从机

redis-server {path}/redis6380.conf     //启动从机
redis-server {path}/redis6381.conf     //

查看主从机,登录主机可以使用如下命令查看从机,反义亦可。

info replication 

更换主机,比如从机更换新主机,可以直接输入命令

replicaof newip newport  

从机变主机

replicaof no one

2.增加哨兵配置

修改sentinel.conf文件,然后复制三分,分别命名sentinel26379.conf,sentinel26380.conf,sentinel26381.conf 修改port

protected-mode no
port 26379
sentinel monitor mymaster 192.168.10.2 6379 2  	//mymaster 自定义主机名,yml配置中需要使用 #192.168.10.2 是主机地址  6379是主机端口 2 是表示多少哨兵同意才更换主机
sentinel auth-pass mymaster 123456				//主机名和密码

启动三台哨兵

redis-sentinel {path}/sentinel26379.conf &  			//后台启动,需要加&符号。
redis-sentinel {path}/sentinel26380.conf & 
redis-sentinel {path}/sentinel26381.conf & 

3.集群配置

新建文件夹cluster,复制主机的配置文件并修改为redis7001.config,redis7002.config,redis7003.config,redis7004.config,redis7005.config,redis7006.config文件后,修改如下配置,

daemonize yes   //修改为后台启动
port 7001  //修改端口号
dir /usr/local/redis-app/7001/     //指定数据文件存储位置
cluster-enabled yes        //开启集群模式
cluster-config-file nodes-7001.conf      集群节点信息文件配置
cluster-node-timeout 15000   集群节点超时间
bind 0.0.0.0     //bind 127.0.0.1 -::1 (这里没写错就是家#注释掉bind配置
protected-mode no			 //关闭保护模式
appendonly yes				//开启aof模式持久化
requirepass 123456		//设置连接Redis需要密码123(选配)
masterauth 123456		//设置Redis节点与节点之间访问需要密码123(选配)

配置好上面的六台机(配置不同的端口与文件)后启动起来。

redis-server {path}/redis7001.conf 
redis-server {path}/redis7002.conf 
redis-server {path}/redis7003.conf 
redis-server {path}/redis7004.conf 
redis-server {path}/redis7005.conf 
redis-server {path}/redis7006.conf 

查看启动的redis都是以cluster方式启动的,就对了

ps -ef | grep redis  

创建集群

// --cluster-replicas 1 表示一台主机配一台从机,redis1Ip:redis1Port redis2Ip:redis2Port …表示所有参与集群的redis IP和端口号,启动成功的话,会自动分配一主一从,自动分配hash槽位。

自动分配hash槽位1

redis-cli -a 123456 --cluster create --cluster-replicas 1 redis1Ip:redis1Port  redis2Ip:redis2Port ...				

案例及过程如下:

[root@hecs-84054 cluster]# redis-cli -a 123456 --cluster create --cluster-replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 127.0.0.1:7005 to 127.0.0.1:7001
Adding replica 127.0.0.1:7006 to 127.0.0.1:7002
Adding replica 127.0.0.1:7004 to 127.0.0.1:7003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 7cc65245058a7bba6518131d522e91dd322c8c00 127.0.0.1:7001
   slots:[0-5460] (5461 slots) master
M: 5c1cacface2f46da888019d1ea1d4fe2ce60326e 127.0.0.1:7002
   slots:[5461-10922] (5462 slots) master
M: c5cf1c8c664f39f959512cc3d4c2262fc5a35f8e 127.0.0.1:7003
   slots:[10923-16383] (5461 slots) master
S: 80df14ea50b39d9f90839584afab600063c3698f 127.0.0.1:7004
   replicates c5cf1c8c664f39f959512cc3d4c2262fc5a35f8e
S: a455c55e476d6ff1eb05df95a682aaea3f8987e0 127.0.0.1:7005
   replicates 7cc65245058a7bba6518131d522e91dd322c8c00
S: e6c82df8271014f5878f46b9d9a40315ac8f6828 127.0.0.1:7006
   replicates 5c1cacface2f46da888019d1ea1d4fe2ce60326e
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join

>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: 7cc65245058a7bba6518131d522e91dd322c8c00 127.0.0.1:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: e6c82df8271014f5878f46b9d9a40315ac8f6828 127.0.0.1:7006
   slots: (0 slots) slave
   replicates 5c1cacface2f46da888019d1ea1d4fe2ce60326e
M: c5cf1c8c664f39f959512cc3d4c2262fc5a35f8e 127.0.0.1:7003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: a455c55e476d6ff1eb05df95a682aaea3f8987e0 127.0.0.1:7005
   slots: (0 slots) slave
   replicates 7cc65245058a7bba6518131d522e91dd322c8c00
M: 5c1cacface2f46da888019d1ea1d4fe2ce60326e 127.0.0.1:7002
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 80df14ea50b39d9f90839584afab600063c3698f 127.0.0.1:7004
   slots: (0 slots) slave
   replicates c5cf1c8c664f39f959512cc3d4c2262fc5a35f8e
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@hecs-84054 cluster]#

如果上面的创建集群失败,可以手动连接参与集群的redis,手动分配hash槽位。如下操作:
集群都启动后,但是还未相互连接时,可以手动连接
首先登录任何一台redis,假设登录第一台7001

redis-cli -a 123456 -p 7001
cluster meet redis1Ip:redis1Port   //运行5次,把其他机器都连接起来。

自动分配hash槽位2

redis-cli --cluster fix redis1Ip:redis1Port		 //redis1Ip:redis1Port 表示任何一台redis的IP与端口

连接后查看节点信息,查看nodeId. 如果看不到所有机器,说明创建失败,需要手动,连接和分配。

redis-cli -a 123456 -p 7001 cluster nodes | awk '{print $1,$2,$3}' // 

查看结果类似这样应该3个master,3个slave;第一个字符串是redisId ,手动分配hash槽位需要用到。

a71582c5f489ed22b64ff72be43be8578eec43ff 127.0.0.1:7004@17004 master   
2004d3c5f489ed22b64ff72be43be8578eecfa70 127.0.0.1:7005@17005 master   
:q 127.0.0.1:7001@17001 myself,master 4438
c9e86cec96b16291bc2a7158220a78211fcde7d6 127.0.0.1:7003@17003 slave
c17c264aeccdf2601b430430d7832f72d6c7eca3 127.0.0.1:7006@17006 slave
336f5a9285c36c9e64037a536ec55c4dfae59401 127.0.0.1:7002@17002 slave

我的就是自动分配了5太主机,1台从机,所以需要再手动分配。
查看hash槽位分布

redis-cli -a 123456 --cluster check redis1Ip:redis1Port  

如果hash槽位分配不合理,主从分配不合理,可以再手动分配。如下:假设自动分配成了4主2从,则需要手动,先把其中一个主机的hash槽位清空,操作如下

手动分配槽位

第一种重新分布hash槽位,可以从多台移动到一台

redis-cli --cluster reshard 127.0.0.1:7005 -a 123456 //重新分布hash,127.0.0.1:7005  表示任意一台redis的ip和端口。

[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)?  8000     //意思是你想移动多少hash槽位,比如输入8000,大于了需要清空那台所占据的槽位数就可以清空掉了。
What is the receiving node ID?  336f5a9285c36c9e64037a536ec55c4dfae59401 //接受hash的nodeId

Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:      all       // 输入all 的意思就是,剩下的几个主机一起移动8000的hash到目标node中。
或者输入
Source node #1:   2004d3c5f489ed22b64ff72be43be8578eecfa70  		// 输入单个源Redis的id,回车再输入
Source node #2:   done												//表示只有从上面这台移动,也可以再添加一台。再回车输入done
Do you want to proceed with the proposed reshard plan (yes/no)?  //输入yes 执行,no 退出

第二种重新分布hash,一步到位,但是只能从一台移动到另一台。
127.0.0.1:7003 表示集群中任何一台redis的IP:port # cluster-from 源redis的ID标识 # cluster-to 目标redis的ID标识 # cluster-slots 是可以获得的最大槽位n

redis-cli --cluster reshard 127.0.0.1:7003 --cluster-from sourceId  --cluster-to targetId --cluster-slots n  

重新分配为从机

reids-cli -a 123456 -p 6379   //登录清空了的主机。
cluster replicate targetId // 复制主机,使其变成从机,

当配置好3主3从后,可以使用下面的命令重新给3太主机平均分配hash槽位

redis-cli -a 123456 --cluster rebalance 127.0.0.1:7001 

集群的相关命令

redis-cli -a 123456 -p 7001 cluster nodes | sort -k3 //查看nodeId.

redis-cli -a 123456 -p 7001 cluster info 		//查看集群结构

redis-cli -a 123456 --cluster check 127.0.0.1:7001 //查看集群hash槽位分布 127.0.0.1:7001 表示集群任何一台redis

redis-cli  --cluster del-node 10.133.0.217:7005 9a3196b7aabf7524da452ca665b93c2fef7bb417 //删除一个从节点或者没有槽位的主节点,注意是一定没有槽位# 10.133.0.217:7005要被删除的redis节点  # 9a3196b7aabf7524da452ca665b93c2fef7bb417节点的ID标识

redis-cli --cluster add-node   10.133.0.217:7005 10.133.0.217:7006 //添加一个主节点 # 第一个IP:PORT 是要加入集群的节点,后一个是任意已存在的节点

redis-cli --cluster add-node  --cluster-slave  --cluster-master-id 3bf112e8fab64ddae44eaf33c7c13eff1a536112 10.133.0.21:7001 10.133.0.217:7002  //添加一个从节点 (未测试过)

java客户端jedis

pom.xml

<!-- Redis-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
	<exclusions>
		<!-- 不依赖Redis的异步客户端-->
		<exclusion>
			<groupId>io.lettuce</groupId>
			<artifactId>lettuce-core</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<!-- jedis客户端-->
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
</dependency>

application.yml 配置

spring:
  redis:
    password: 123456
    timeout: 1000
    jedis:
      pool:
        max-wait: 1s
        max-idle: 10
        max-active: 20
        min-idle: 5
    
   #集群模式
	cluster:
	  nodes: 127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005,127.0.0.1:7006
	  max-redirects: 5
	  
	#单机或主从模式
    #host: ip
    #port: 6379
    
    #主从+哨兵模式
    #sentinel:
      #master: mymaster
      #哨兵节点
      #nodes: ip:port,ip:port,ip:port

java 文件
RedisConfig.java

@Configuration
public class RedisConfig 
{
	@Autowired
	private RedisTemplate redisTemplate = null;
	
	@PostConstruct
	public void init() 
	{
		RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
		redisTemplate.setKeySerializer(stringSerializer);
		redisTemplate.setValueSerializer(stringSerializer);
		redisTemplate.setHashKeySerializer(stringSerializer);
		redisTemplate.setHashValueSerializer(stringSerializer);
		System.out.println("redis init done");
	}
}

AccountController.java

@Controller
@RequestMapping("/fund")
public class AccountController {

	@Autowired
	private RedisTemplate redisTemplate;
	@GetMapping("/write/{id}") // @GetMapping代表GET请求
    @ResponseBody // 结果转换为JSON
    public Map<String,String> setAccount2(@PathVariable("id") Long id) {
    	Map<String,String> result = new HashMap<String,String>();
    	result.put("user"+id, id+"");
    	redisTemplate.opsForValue().multiSet(result);
        return result;
    }
    
    @GetMapping("/read/{id}") // @GetMapping代表GET请求
    @ResponseBody // 结果转换为JSON
    public Map<String,String> getAccount2(@PathVariable("id") Long id) {
    	Map<String,String> result = new HashMap<String,String>();
    	result.put("user"+id, (String)redisTemplate.opsForValue().get("user"+id)+ 1);
        return result;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芊芸爸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值