redis常用命令

set/mset

get/mget

hset/hmset

hget/hmget/hgeteall

del

exists

type ,value的类型

ttl ,key的剩余存活时间

expire/pexpire,可作为set的参数结合成一条命令

expireat/pexpireat,设置时间点过期,时间用unixtime表示

persist ,取消key的过期时间设置

keys ,后面支持简单的pattern,如任意长度字符,?任意一个字符,[]中括号里面的字符

incr/incrby/incrbyfloat,decr/decrby

setbit/getbit/bitop/bitcount

flushdb,删除当前库所有的key,操作不安全,建议使用shell代替

redis的bitmap的使用

主要适用场景是海量数据的计算。特点是速度快。占用空间小.
1.setbit key offset value ,offset,key可以设置有意义。offset用有意义的数字代替,value,只能是1或0,因为是bit.分配一个key的内存,然后在内存的“位”上填充1或者0
2.操作:
a)统计bit:bitcount key start end_ //不指定start,end,默认是所有位移位置
b)位运算:bitop and k1 k2 //支持四种位运算:and or xor not

3.统计签到人数

  setbit 2020-03:u1 1 1  //设置u1用户3月份1号签到
  setbit 2020-03:u1 5 1  //设置u1用户3月份5号签到
  setbit 2020-03:u1 31 1  //设置u1用户3月份31号签到

  bitcount 2020-03:u1  1 31 //位运算“1”出现的次数是3次,默认是所有位移,也可以指定位移量

4.计算活跃用户

 setbit 0308 1 1
 setbit 0308 2 1
setbit 0309 1 1
 setbit 0310 2 1

bitop and desk1 0308 0309 0310  //计算连续登录活跃用户
bitcount desk1

bitop or desk2 0308 0309 0310  //至少登录一天的活跃用户
bitcount desk2

基于redis的唯一ID生成器

https://blog.csdn.net/wind_2307154495/article/details/78739498

1.ID生成中心每次从Redis(使用incr命令)中获取一定范围的递增ID区间(该区间范围相对大一些,eg:10000),并同步缓存至L1、L2(避免大量ID区间丢失)。

2.当该应用的该IDKey的ID区间使用率超过一定阈值(eg:>50%)时,ID生成中心自动从Redis(使用incr命令)中获取下一个递增ID区间,缓存至L1、L2,减少消费耗时。

3.当ID生成中心宕机,再次启动时,会优先同步L2中的ID区间至L1中,如果没有再从Redis中通过incr获取,已达到节约ID的目的。

4.这里L1、L2的ID数据同步是异步进行的。

5.ID生成客户端的基本设计思路也是差不多一样的。只不过这是获取的ID区间相对ID生成中心从Redis获取的ID区间会小很多,这里尽量保证俩者区间段有一个相当大的比例区间。对于获取的ID区间具体大小,可以根据个人的需求取舍。


扩展:生成全局唯一ID/数据库主键ID的方法
a)数据库自增长:性能较差
b)取到毫秒+随机数:还有会存在高并发问题
c)UUID:
d)批量ID生成服务:使用vip+keepalived可增加性能可用性。redis方案属于这样,中小型项目可以使用些方案。
e)类snowflake算法,分布式项目中常用方法

redis基础复习

1.问题

a)海量用户
b)高并发
c)磁盘IO性能低
d)关系型数据库的关系复杂

2.解决

a)减少IO次数
b)降低数据间关系,越简单越好

3.noSQL:not only SQL,不仅仅是sql,作为关系型数据的补充,而不是替代

4.电商使用存储的案例:

a)商品信息:mysql
b)商品描述信息:mongodb
c)图片:分布式文件系统中
d)搜索关键字:es
e)热点关键信息:redis。。

5.特征:弱数据关系,单线程,高性能,多数据类型,可持久化(RDB,AOF)

6.应用场景,列举

a)热点数据查询(主要场景)
b)统计数据
c)队列
d)时效性控制(如验证码过程)
e)分布式数据共享(如session共享)
f)分布式锁
g)“感兴趣”功能

7.基本命令操作:

a)help:如help set
b)clear
c)set/get/del
d)expire/pexpire

8.数据类型,常用五种:string,list,hash,set,zset 。其他如:BitMap(并不是真正的类型,定义在string类似中),HyperLogLog

9.string:最常用的,当为数字时,实际上也是string只是能当数字使用。

 a)补充基本操作set/mset,get/mget/,del,strlen,append
 b)多指令相对总时间会比较短,但当使用多指令mset时,会照成单次执行等待时间增多,影响get的延迟。
 c)对数值的操作:incr 整数自增长1,incrby 整数增长指定的整数值,incrbyfloat 浮点增长指定的浮点值,decr整数自减,decrby 整数减指定的整数值。因为支持负数,其他不一定两个同时用。
 d)redis是单线程操作,每一个操作都是原子性的,所以无须考虑高并发下的问题,可以用来生成唯一主键!!!!
 e)时效性操作:
   set k v ex 1 //设置1秒过期,单独命令expire的快捷使用
   set k v px 1 //设置1毫秒过期,单独命令的pexpire的快捷使用
 f)string类型常用k-v设计:
   表名:主键名:主键值:字段名 字段值,如set user:id:100001:fans 879//单值,操作更方便,但数据不集中,比较分散
   表名:主键名:主键值  {字段名:字段值}如:set user:id:100001 {fans:879,blogs:200}//json字符串,数据更集中,不方便修改,方便对象读

10.hash.

a)为了解决string类型中,数据结构存储的不足,方便对象写,类似对象的方式,无序的。hset key filed value
b)基本操作:hset/hget/hgetall,hmset,hincr….;
c)实现登录状态下的购物车实践:
“`
hmset cart:userid:1001:nums good01 100 good02 200 //存储数量
hmset cart:userid:1002:nums good02 400 good03 10 //存储数量

hmsetnx good:id:good01:info {json} //存储商品信息描述,公共信息
hmsetnx good:id:good02:info {json} //存储商品信息描述,公共信息
d)抢购:
hmset p01 c30 1000 c50 1000 c100 1000
hincrby p01 c100 -20
“`
e)hash存储对象与sting存储json对象的区别:
hash注重写,string的json注重读

11.list

a)string,hash中常用存储单个对象数据,当需要保存多个数据时,用到了list
b)顺序表,单向链表,双向链表,循环链表,redis中的list属于双向链表
c)进入顺序,左进和右进。
微信截图_20200309213343
e)常用操作:lpush/rpush,lrange/lindex/llen,lpop/rpop,push后的数据是按左到右的排列顺序。常用rpush进入,比较符合人习惯。
127.0.0.1:6379> lpush list1 a b c //左推入abc
(integer) 3
127.0.0.1:6379> lrange list1 0 2 //查看0到2的位置数据(此时可以看出排列顺序是从左到右)
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> lpop list1 //左移出默认的一个数据
"c"
127.0.0.1:6379> rpop list1 //右移出默认的一个数据
"a"

f)blpop/brpop key timeout:阻塞broke等待pop操作。timeout是等待的秒数,移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。(多个key也是相同的超时时间)
blpop list1 30 //如果有数据,则立即返回,没有则最多等待30秒,中间等待时如有数据则立即返回
1) "list1"
2) "b"

g)lrem key count value 删除指定等于value的值个数,假如value有多个一样的值。
//朋友圈点赞
127.0.0.1:6379> rpush 1001 a b c d //给朋友圈1001号信息,abcd四个人点赞
(integer) 4
127.0.0.1:6379> lrange 1001 0 -1 //查看1001的所有点赞人,使用-1表示最后一个元素的索引
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379> lrem 1001 1 c //c取消自己的赞
(integer) 1
127.0.0.1:6379> lrange 1001 0 -1 //现次查看1001的所有点赞人
1) "a"
2) "b"
3) "d"

f)实例:分布式消息聚合时,最新数据展示,使用list实现,单线程/自带顺序(不需要排序ID)
“`
cmd:rpush logs a1
cmd:rpush logs b2

cmd:lrange logs 0 -1 //会显示有先后顺序的数据
### 12.set
a)list能存大量数据,但却在存储过程中因为是链表的形式不方便,所以出现了set数据类型
b)set是hash的变形,hash的key后面的field只是相当于一个子key,真正的数据在最右边,浪费了field的存储空间。所以set相当于去掉hash右边的value,直接拿field作为value(member),同时field是不能相同的,也就是set是不允许相同的value(member).
<img src="http://www.tanguu.com/wp-content/uploads/2020/03/微信截图_20200309230625.png" alt="微信截图_20200309230625" width="425" height="347" class="alignnone size-full wp-image-3758" />
<img src="http://www.tanguu.com/wp-content/uploads/2020/03/微信截图_20200309230644.png" alt="微信截图_20200309230644" width="534" height="348" class="alignnone size-full wp-image-3757" />
c)基本操作
sadd key member1 member2... //增加
smembers key //查询,member后面有个“s”
srem key member //删除
scard key //统计长度/个数
d)扩展操作1:应用案例:随机推荐
srandmember key count 随机取数据不删除
spop key count随机取数据但同时会删除

e)扩展操作2:应用案例:相同好友推荐
交,并,差集
sinter/sunion/sdiff
sinterstore/sunionstore/sdiffstore 会找到新集合到新的set中

127.0.0.1:6379> sadd user1 a1 a2 a3
(integer) 3
127.0.0.1:6379> sadd user2 a1 a3 a4
(integer) 3
127.0.0.1:6379> sinter user1 user2
1) “a3”
2) “a1”
127.0.0.1:6379> sunion user1 user2
1) “a4”
2) “a1”
3) “a3”
4) “a2”
127.0.0.1:6379> sdiff user1 user2
1) “a2”
127.0.0.1:6379> sdiff user2 user1
1) “a4”
“`
f)注意事项:不允许重复member

13.zset:有序集合,多了一个scorer用来排序

a)zadd key score member1 member2… //增加
即有set的功能也有list排序功能,所以zset的操作命令跟 set和list有部分差不多

b)list set zset的区别:
微信截图_20200310015904

14.redis持久化方式:RDB、AOF

a) RDB:数据快照,每隔一段时间作一次数据快照,在配置文件中可以设置自动快照策略。也可以手动输入save命令(bgsave不阻塞),手动快照。
b)AOF:为了解决RDB在定时快照的缺点,写日志方式,写操作时才记录(类似于myslq的binlog),默认不开启,因为比较耗性能。可以设置每秒写操作或者每一条写操作记录或者不设置。
当aof文件出错时,可以使用redis_check_aof修复
c)性能测试:redis-benchmark

15.支持lua脚本

16.无中心化的集群,集群是为了数据分片:使用哈希槽分配

a)使用算法得到得到值,再取16384的模,就知道放到哪个哈希槽里。
b)哈希槽在每个节点上不一定
微信截图_20200310013233

17.比较简单配置的主从配置,主从是为了读写分离,高可用

18.事务机制,原子性,出错但不会回滚,因为不需要回滚

只有当发生语法错误(这个问题在命令队列时无法检测到)了,Redis命令才会执行失败, 或对keys赋予了一个类型错误的数据:这意味着这些都是程序性错误,这类错误不需要redis回滚支持,在开发的过程中就能够发现并解决掉,几乎不会出现在生产环境。
由于不需要回滚,这使得Redis内部更加简单,而且运行速度更快。
a)MULTI标记一个事务块的开始。
b)EXEC执行所有事务块内的命令。
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set num1 1
QUEUED
127.0.0.1:6379> set num2 2
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK