数据类型
命令不区分大小写,而key是区分大小写的
- string 字符
- 最常用
- set key value
- get value
- 如何同时获取多个键值
- mset key value[key value ...]
- mget key[key...]
- 数值增减
- 递增数字 incr key
- 增加指定的整数 incrby key increment
- 递减数值 decr key
- 减少指定的整数 decrby key decrement
- 获取字符串的长度 strlen key
- 分布式锁
- setnx key value
- set key value[EX seconds] [Px milliseconds] [NX|XX]
- Ex:key 在多少秒后过期
- PX:key在多少毫秒后过期
- NX:当Key不存在的时候,才创建key,效果等同于setnx
- XX:当key存在的时候,覆盖key
- 应用场景
- 商品编号,订单编号采用incr 命令生产
- 是否喜欢的文章
- list 列表
- 向列表左边添加元素 lpush key value[value...]
- 向列表右边添加元素 rpush key value[value...]
- 查看列表 lrange key start stop
- 获取列表中元素的个数 llen key
- 应用场景 微信文章订阅公众号
- hash 散列
- 对应Map<String,Map<Object,Object>>
- 一次设置一个字段值 hset key field value
- 一次获取一个字段值 hget key field
- 一次设置多个字段值 hset key field value[field value ..]
- 一次获取多个字段值 hget key field[fiela ..]
- 获取所有字段值 hgetall key
- 获取某个key内的全部数量 hlen
- 删除一个key hdel
- 应用场景购物车简单版
- set 集合
- 添加元素 sadd key member[member...]
- 删除元素 srem key member[member...]
- 获取集合中的所有元素 smembers key
- 判断元素是否在集合中 sismember key member
- 获取集合中的元素个数 scard key
- 从集合中随机弹出一个元素,元素不删除 srandmember key[数字]
- 从集合中随机弹出一个元素,出一个删一个 spop key[数字]
- 集合运算
- 差集 A-B sdiff key [key ...]
- 交集 A∩B sinter key[key...]
- 并集 A∪B sunion key [key...]
- 应用场景
- 抽奖小程序
- 朋友圈点赞
- 微博好友关注社交关系
- 共同关注的人 交集
- 我关注的人别人也关注了他。
- qq内推可能认识的人 差集
- zset(sorted set) 有序集合
- 向有序集合中加入一个元素和该元素的分数
- 添加元素 zadd key score member[score member...]
- 按照元素分数从小到大顺序返回索引从start到stop之间的所有元素 zrange key start stop[withscore]
- 获取元素的分数 zscore key member
- 删除元素 zrem key member[member ...]
- 获取指定分数范围的元素 zrangebyscoer key min max [withscore]
- 添加某个元素的分数 zincrby key increment member
- 获取集合中元素的数量 zcard key
- 获得指定分数范围内的元素个数 zcount key min max
- 按照排名范围删除元素 zremrangebyrank key start stop
- 获取元素的排名
- 从小到大 zrank key member
- 从大到小 zrever key member
- 应用场景
- 根据商品销售对商品进行排序显示
- 抖音热搜
- bitmap 位图
- HyperLogLog 统计
- GEO 地理空间
- Stream
分布锁
知道分布式锁嘛?有那些实现方案?
分布式微服务架构,拆分后各个微服务为了避免冲突和数据故障而加入的一种锁,分布式锁
解决方案
1、mysql
2、zookeeper
3、redis
redis---redlock===>redisson lock/unlock
服务加锁
单机版加锁
sychronized或者lock
设置超时时间的或用lock.trylock(1L,TimeUnit.单位)
Nginx负载均衡
/usr/local/nginx/conf nginx.conf
设置负载均衡
/usr/loacl/nginx/sbin/nginx -c/usr/loacl/nginx/conf/nginx.conf
./nginx -c/usr/local/nginx/conf/nginx.conf
- 启动 /usr/local/nginx/sbin
- 关闭 /usr/local/nginx/sbin ./nginx -s stop
- 重启 ./nginx -s reload
分布式锁
1、
String value=UUID.randomUUID().toString()+Thread.currentThread().getName(); Boolean flag=stringRedisTemplate.opsForValue().setIfAbsent(REDIS_LOCK,value); if(!flag){ //抢锁失败 }
2、如果异常的话,可能无法释放锁,必须要在代码层面finally释放锁
String value=UUID.randomUUID().toString()+Thread.currentThread().getName(); try{ Boolean flag=stringRedisTemplate.opsForValue().setIfAbsent(REDIS_LOCK,value); if(!flag){ //抢锁失败 } }finally{ stringRedisTemplate.delete(REDIS_LOCK) }
3、宕机了怎么解决,机器挂了代码走不到finally key没有办法删除
需要加入一个过期时间
String value=UUID.randomUUID().toString()+Thread.currentThread().getName(); try{ Boolean flag=stringRedisTemplate.opsForValue().setIfAbsent(REDIS_LOCK,value); stringRedisTemplate.expire(REDIS_LOCK,10L,TimeUnit.SECONDS);//10秒过期 if(!flag){ //抢锁失败 } }finally{ stringRedisTemplate.delete(REDIS_LOCK) }
4、原子性怎么保证?
String value=UUID.randomUUID().toString()+Thread.currentThread().getName(); try{ Boolean flag=stringRedisTemplate.opsForValue().setIfAbsent(REDIS_LOCK,value,10L,TimUnit.SECONDS); if(!flag){ //抢锁失败 } }finally{ stringRedisTemplate.delete(REDIS_LOCK) }
5、锁时间过期,误删其他的锁
String value=UUID.randomUUID().toString()+Thread.currentThread().getName(); try{ Boolean flag=stringRedisTemplate.opsForValue().setIfAbsent(REDIS_LOCK,value,10L,TimUnit.SECONDS); if(!flag){ //抢锁失败 } }finally{ //加判断 是不是自己的锁 if(stringRedisTemplate.opsForValue().get(REDIS_LOCK).equalsIgnoreCase(value)){ stringRedisTemplate.delete(REDIS_LOCK) } }
6、判断和delete不是原子性的,会造成误解锁
- lua脚本解决
if redis.call("get",KEYS[1]==ARGV[1]) then return redis.call("del",KEYS[1]) else return 0; end
- redis的事务
- MULTI 标记事务块的开始
- EXEC 事务中执行所有先前放入队列的命令,然后恢复正常的链接状态
- DISCARD 所有先前在一个事务中放入队列的命令,然后恢复正常的链接状态
- wacth 某个事务需要按条件执行时,就要使用这个命令将给定的建设为监控的状态 wacth key
- unwacth 清空监控的建
String value=UUID.randomUUID().toString()+Thread.currentThread().getName(); try{ Boolean flag=stringRedisTemplate.opsForValue().setIfAbsent(REDIS_LOCK,value,10L,TimUnit.SECONDS); if(!flag){ //抢锁失败 } }finally{ while(true){ stringRedisTemplate.watch(REDIS_LOCK);//标记为监听状态 //加判断 是不是自己的锁 if(stringRedisTemplate.opsForValue().get(REDIS_LOCK).equalsIgnoreCase(value)){ stringRedisTemplate.setEnableTransactionSupport(true);//支持事务 stringRedisTemplate.muti(); stringRedisTemplate.delete(REDIS_LOCK); List<Object> list=stringRedisTemplate.exec();//返回队列 if(list!=null){ continue; } } stringRedisTemplate.unwatch();//清楚监控 break; } }
7、redis池
String value=UUID.randomUUID().toString()+Thread.currentThread().getName(); try{ Boolean flag=stringRedisTemplate.opsForValue().setIfAbsent(REDIS_LOCK,value,10L,TimUnit.SECONDS); if(!flag){ //抢锁失败 } }finally{ Jedis jedis=RedisUtils.getJedis(); String script="if redis.call('get',KEYS[1])==ARGV[1]" +"then"+ "return redis.call('del',KEYS[1])"+ "else"+ "return 0;"+"end" try{ Object 0=jedis.eval(script,Collections.singletonList(REDIS_LOCK),Collections.singletonList(value)); if("1".equals(o.toString()){ //成功 }else{ //失败 } }finally{ if(null!=jedis){ jedis.close(); } } }
9、确保Redislock过期时间大于业务执行时间的问题
redis分布锁如何续期? 缓存续命机制
特性:AP
C:Consistency(强一致性)
A:Availability(可用性)
P:Partition tolerance(分区容错性)
AP:redis异步复制造成锁丢失
比如主节点没来得及把刚刚的set进来这条数据给从节点,就挂了
zookeperCP
Redisson
//配置 @Bean public Redisson redisson(){ Config config=new Config(); config,useSingleServer().setAddress("redis://192.168.111.147:6379").setDatabase(0); return (Redission)Redisson.create(config); }
//分布式锁调优 private Redisson redisson; .... String value=UUID.randomUUID().toString()+Thread.currentThread().getName(); RLock lock=redisson.getLock(REDIS_LOCK); lock.lock(); try{ //逻辑 if(!flag){ //抢锁失败 } }finally{ lock.unlock(); }
问题,不要直接写unlock(); //数据量过大时,会报解锁的线程不是要解锁的线程
//分布式锁调优 private Redisson redisson; .... String value=UUID.randomUUID().toString()+Thread.currentThread().getName(); RLock lock=redisson.getLock(REDIS_LOCK); lock.lock(); try{ //逻辑 if(!flag){ //抢锁失败 } }finally{ if(lock.isLocked()){//是加锁状态 if(lock.isHeldByCurrentThread){//是本线程持有 lock.unlock(); } } }
redis缓存过期淘汰策略
- Redis内存满了怎么办
会报oom
- 默认内存多少?在哪里查看? 怎么设置 怎么查看内存情况?
reids.config maxmemory参数 如果不设置 64不限制大小,32位3个G
一般设置位最大内存的四分之三
1、通过文件配置 2、命令配置 config set maxmemory 单位
info memory
- redis的淘汰策略 8个
- 删除策略
1、默认打满报错
定时删除(对cpu不好,对内存好) 惰性删除(对内存不好,对cpu好),
定期删除(每个一段时间执行一次,限制删除的时长和频率)
设置 config set maxmemory-policy 策略
LRU算法 最近最少使用,常用搞得页面置换算法
redis,缓存
读+写两个操作。
命中
哈希链表