redis学习

redis学习

本文为学习《Redis深度历险》的学习笔记

第一章 基础和应用

1.1、redis安装

redis支持dock安装和直接安装。

这里使用github镜像https://github.com/tporadowski/redis/releases

将下载下来的zip包解压,放到合适的位置(这里放在了D:\redis)

进入D:\redis,打开cmd命令行运行下列命令启动服务端

redis-server.exe redis.windows.conf

另起一个窗口运行下列命令启动客户端

redis-cli.exe -h 127.0.0.1 -p 6379

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ii8hDZBZ-1622899251406)(.\images\permissionDenied.png)]

RDB文件读取失败

如果redis报以上错误,说明redis没有权限读取rdb文件,查看redis.windows-service.conf的working directory是否在c盘,将其改成其他盘即可。

1.2、redis数据结构

1.2.1、String

1、Redis中String是动态String,类似于Java中的ArrayList。

2、扩容:当字符串长度小于1MB时加倍扩容,当字符串长度大于1MB时每次扩容1MB,Redis的String长度最大是512MB。

3、crud

#插入一条记录,key=name,value=codehole
set name codehole
#获取name
get name
#判断key是否存在
exists name
#删除
del name

批量操作

set name1 codehole
set name2 holycoder
#批量查询
mget name1 name2
#批量插入
mset name3 value3 name4 value4
mget name1 name2 name3 name4

设置过期

set name value
expire name 5 #设置name的过期时间为5s

数值型字符串

#如果value是一个整数,redis提供了自增操作,redis的整数最大是Long.Max,即9223372036854775807,超出这个值会报错
set age 30
#自增操作
incr age
#加5
incrby age 5
incrby age -5
1.2.2、List

Redis中List相当于Java语言里的LinkedList,Redis中的List是双向列表,支持rpush、rpop、lpush、lpop操作。

1、curd

由于redis中的list是双向列表,所以可以实现队列和栈两种数据结构。

队列:

#从右侧向books列表中插入3条数据
rpush books java python go
#查询列表长度
llen books
#从左侧取出一条数据,此时的list相当于一个队列(先进先出)
lpop books
>"java"
lpop books
>"python"
lpop books
>"go"

栈:

#从右侧向books插入三条数据
rpush books java Python go
#从右侧取出一条数据,此时的list相当于一个栈
rpop books
>go
rpop books
>python
rpop books
>java

lindex和ltrim操作

lindex:类似于java中链表的get(int index)操作,其时间复杂度为O(n)。index可以为负数,0表示第一个元素,-1表示倒数第一个元素。

ltrim:类似于java中String的trim,有两个参数start_index和end_index,保留着两个参数之间的元素。

rpush books java Python go
lindex books 1 #取出第二个元素
>python
lrange books 0 -1 #获取所有元素
ltrim books 1 -1 #保留第二个元素到最后一个元素
ltrim books 1 0 #删除所有元素

redis的list底层使用“快速链表”(quicklist)实现。它是由多个压缩列表(ziplist)通过双向指针连接而成。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v6lMuZEw-1622899251408)(.\images\1.3quicklist.png)]

quicklist结构图
1.2.3、hash

redis中的字典相当于java中的hashmap,无序,以数组+链表的二维结构。redis字典的value只能是String,且redis为了不阻塞服务,使用渐进式rehash策略逐步替换旧的hash结构。

curd

#向books散列添加一个键值对
hset books java "think in java"
hset books go "concurrency in go"
#获取元素
hget books
#获取散列中的所有元素
hgetall books
#获取长度
hlen books
#批量插入
hmset books java "effective java" python "learning python"

hash的value如果是整型也支持自增操作

hset human age 28
#自增操作
hincrby human age 1
1.2.4、set

redis中的set类似于java中的hashset

curd

sadd books python
sadd books java
#列出set中所有元素
smembers books
#查询某个元素是否存在
sismember books rust
#查询set集合大小
scard books
#弹出一个元素
spop books
1.2.5、zset

redis中的zset类似于java中的sortedSet和HashMap的结合体,通过一个score对元素进行排序。

zadd books 9.0 "think in java"
zadd books 8.5 "learning python"
zadd books 8.0 "golang"
#列出所有元素,按score顺序排出(从小到大)
zrange books 0 -1
#列出所有元素,按score逆序排出(从大到小)
zrevrange books 0 -1
#查询zset大小
zcard books
#查询单个元素得分大小
zscore books "think in java"
#查询单个元素排名,从0开始
zrank books "think in java"
#遍历分值范围内的元素
zrangebyscore books 0 8.9
#遍历元素,并返回对应的score,-inf表示负无穷大
zrangebyscore books -inf 8.9 withscore
#删除元素
zrem books "golang"

跳表:参考https://www.cnblogs.com/hunternet/p/11248192.html

1.2.6、过期时间

1、redis所有对象都支持过期时间设置

2、如果一个字符串设置了过期时间,但是又使用set方法修改,过期时间会失效

3、redis失效是一整个对象失效,比如hash失效是整个hash对象的失效,而非hash中的某个value。

set book codehole
#设置失效时间5s
expire book 5
#查询剩余有效时间
ttl book
#设置失效时间为500毫秒
pexpire book 500

1.3、分布式锁

1.3.1、分布式锁实现

setnx(set if not exists)如果不存在返回1,如果存在返回0

setnx lock true #加锁
del lock #解锁

1、死锁问题,如果某个线程获取到锁之后发生异常退出,其他线程无法再次拿到锁执行。

​ 解决方法:redis锁添加超时时间,一定时间后自动释放锁。

setex lock 5 true #设置lock的过期时间为5s 

2、可重入性,redis本身不支持可重入锁,可以通过客户端代码实现可重入。

public class RedisWithReentrantLock{
    private ThreadLocal<Map<String, Integer>> lockers =new ThreadLocal<>();
    private Jedis jedis;
    
    public RedisWithReentrantLock(Jedis jedis){
        this.jedis = jedis;
    }
    
    private boolean _lock(String key){
        return jedis.set(key,"","nx","ex",5L)!=null;
    }
    
    private void _unlock(String key){
        jedis.del(key);
    }
 
    private Map<String,Integer> currentLockers(){
        Map<String,Integer> refs = lockers.get();
        if(refs!=null){
            return refs;
        }
        lockers.set(new HashMap<>());
        return lockers.get();
    }
    //第一次加锁时使用redis,之后的每次加锁只在本地+1;
    public boolean lock(String key){
        Map<String,Integer> refs=currentLockers();
        Integer refCnt = refs.get(key);
        if(refCnt!=null){
            refs.put(key,refCnt+1);
            return true;
        }
        boolean ok =this._lock(key);
        if(!ok){
            return false;
        }
        refs.put(key,1);
        return true;
    }
    //每次解锁时本地-1,只有最后一次解锁时释放redis
    public boolean unlock(String key){
        Map<String,Integer> refs = currentLockers();
        Integer refCnt = refs.get(key);
        if(refCnt==null){
            return false;
        }
        refCnt -=1;
        if(refCnt>0){
            refs.put(key,refCnt);
        }else{
            refs.remove(key);
            this._unlock(key);
        }
        return true;
    }
    
public static void main(String[] args){
    Jedis jedis =new Jedis();
    RedisWithReentrantLock redis =new RedisWithReentrantLock(jedis);
    System.out.println(redis.lock("codehole"));
    System.out.println(redis.lock("codehole"));
    System.out.println(redis.unlock("codehole"));
    System.out.println(redis.unlock("codehole"));
}    
}
1.3.2、锁冲突处理

1、直接抛出异常。这种适合客户端直接发起的请求,可以返回一段文字让用户稍后重试。

2、sleep。sleep会阻碍当前线程,导致队列的后续消息处理出现延迟。

3、延迟队列。将冲突的请求扔到另一个队列延后处理。

**1.4、**使用redis实现简单消息队列

1.4.1、使用redis的list数据结构可以实现简单消息队列,使用lpush和lpop实现消息的生产和消费。

1.4.2、消息空了,消费者会一直pop,导致redis性能问题怎么办?

​ 答:消息为空时让消费者sleep,以减少redis压力。

1.4.3、sleep会造成消费延迟,比如sleep1秒,当list为空时下一次消费会在一分钟后,如果此时来了消息会有一分钟延迟,怎么办?

​ 答:使用blpush和blpop实现阻塞读,当读不到内容时阻塞当前线程,直到来消息。

1.4.4、使用阻塞读如何应对空闲连接自动断开问题(一定时间内没有生产消息连接会自动断开)?

​ 答:捕获异常,对异常进行处理(报错或重新连接)。

1.4.5、延迟队列实现代码

//暂无

1.5、位图(bitmap)

顾名思义,使用bit存储。比如记录一个员工365天哪几天打卡,如果使用hash结构,其存储空间是惊人的,如果使用位图,只需要365/8+1=46个字节。

1、位图操作

比如h的ASCII码是0b1101000

零存零取

#01101000
setbit str 1 1 #第一位是1
setbit str 2 1 #第二位是1
setbit str 4 1 #第四位是1
get str #获取bitmap对应的string

零存零取

setbit str 1 1 
setbit str 2 1 
setbit str 4 1
getbit str 1 #获取bitmap第一位的值 0或1

整存零取

set str h #整存
getbit str 1 #获取"h"的第1位

bitcount和bitpos

bitcount:统计一定范围内1的个数

bitpos:统计一定范围内第一个出现的0或1

set str hello
bitcount str #获取hello中1的个数
bitcount str 0 1 #获取前两个字符中1的个数(注意一个字符是八位)
bitpos str 0 #查询第一个出现0的位置
bitpos str 1 2 3 #查询第二个字符和第三个字符中第一次出现1的位置

bitfield:可以对bitmap进行多位操作

#he:01101000 01100101
set str he
#从下标为0开始取4位,返回一个无符号数
bitfield str get u4 0
>6
#从下标为2的bit开始取三位,返回一个有符号数
bitfield str get i3 2
>-3 #为什么是-3,我们取到的是 101,第一个位为 1,是符号位数,表示这是个负数。然后我们把 01 取反得 10,然后取补码即 加1 得 11,结果就是 -3 了

1.6、HyperLogLog

背景:记录一个网页每天的UV(unique visitor)。

方法1:使用set集合对用户id进行去重。

​ 优点:实现简单,结果精确。

​ 缺点:如果用户规模上亿,set会很大,存储空间占用多。

方法2:使用HyperLogLog估算。

​ 优点:存储占用少。

​ 缺点:结果不精确,对用户id随机性要求较高。

HyperLogLog提供了两个指令pfadd和pfcount。

pfadd:类似于set的sadd

pfcount:类似于scard

pfadd usrs usr1
pfadd usrs usr2
pfcount usrs

实现原理:HyperLogLog记录value中bit的低位最高连续0出现的长度K,估算出数据量N在2K~2(K+1)之间(实际算法比这复杂多,比如使用桶增加准确性)。

HyperLogLog需要额外12KB的存储空间,因为HyperLogLog使用214个桶,每个桶占6bit,共214*6/8=12KB的空间来存放低位最高连续0的个数。

1.7、布隆过滤器(bloom filter)

原理:将value映射成bit放入bitmap中,查询时对照bitmap。

布隆过滤器如果返回true表示可能存在,如果返回false表示一定不存在。因为映射实际上是一种hash,可能有hash冲突。

bf.add usr usr1 #向布隆过滤器中添加元素
bf.exists urs usr1 #判断是否存

1.8、基于redis的限流器

背景:需要判断一个用户行为是否合法,比如1分钟内点赞次数不能超过5次。

分析:使用用户的点赞行为做key,使用zset存储,将每次请求的时间戳作为score。当一次新点赞时将该行为加入zset中,并且剔除1分钟之前的记录,最后返回zset中集合总数,即为这1分钟内的点赞数。代码如下:

public class SimpRateLimiter{
    private Jedis jedis;
    public SimpRateLimiter(Jedis jedis){
        this.jedis = jedis;
    }
    public boolean isActionAllowed(String usrId,String actionKey,int period,int maxCnt){
        String key = String.format("hist:%s:%s",usrId,actionKye);
        long nowTs=System.currentTimeMillis();
        Pipeline pipe = jedis.pipelined();
        pipe.multi();
        pipe.zadd(key,nowTs,""+nowTs);//添加当前记录
        pipe.zremrangeByScore(key,0,nowTs-period*1000);//删除时间窗口之前的记录
        Response<Long> cnt=pipe.zcard(key);//计算当前时间窗口内记录数
        pipe.expire(key,period+1);//如果下个窗口内没有action则失效当前zset
        pipe.exec();
        pipe.close();
        return cnt.get()<=maxCnt;
    }
    
}

1.9、redis-cell

1.10、GoeHash

背景:微信的附近的人是怎么实现的?

GoeHash算法思想:将地球想像成一个二维平面。将这个平面切割成4块,分别标记为00、01、10、11。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3JtH4hbB-1622899251410)(.\images\geohash1.png)]

再将这四个小块分别细分

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2RCdaqDT-1622899251413)(.\images\geohash2.png)]

最终将一个二维坐标映射成一串二进制数进行存储。

redis中geo的基本用法

geoadd graph 111.48105 39.996794 meituan #添加一个坐标meituan
geoadd graph 111.514203 39.905409 ireader #添加一个坐标掌阅
geodist graph meituan ireader km #计算距离
geopos graph meituan #获取美团的坐标
geohash graph meituan #获取base32编码的hash值,可以去http://geohash.org/${hash}获取真是地址坐标。
georadiusbymember graph ireader 20 km count 3 asc #获取iReader附近20km之内的3个地址,按距离升序排序。

1.11、keys和scan

keys和scan用于返回redis中有哪些key,支持简单的正则表达式。

keys * #获取所有的key
keys j*va #获取带正则表达式的key

keys的缺点:没有offset、limit,只能返回所有结果。

scan的基本用法

scan 0 match java* count 1000 #从游标为为0开始扫描,每次扫描1000个槽位(slot)

这里有两点需要解释:(1)、游标位置不是递增的,因为redis扫描采用高位进位法;(为了应对扩容时不重复扫描)(2)、count 1000也不是会返回1000条数据,这里1000是指会扫描1000个槽位。

并且像set、zset、hash都提供ssan、zscan、hscan来遍历集合的key。

第二章、核心原理

第三章、集群篇

3.1、主从同步

3.1.1、CAP原理:

​ C:Consistent,一致性

​ A:Availability,可用性

​ P:Partition tolerance,分区容错性

网络分区:分布式系统间网络断开的场景。

用一句话概括CAP定理就是,当网络分区发生时,一致性和可用性无法同时满足。

Redis支持主从同步和从从同步

增量同步:redis将指令流存在内存buffer中,然后将buffer中的指令流异步同步到从节点。从节点一边执行指令流一边反馈自己同步到哪了(偏移量)。buffer是一个定长环形数值,这就存在当主从节点隔离较久,数组满了之后后面的指令会覆盖前面的指令,造成数据丢失。

快照同步:主节点先将内存中的所有数据生成一个快照文件,并将这个快照文件发送给从节点。从节点加载这个文件到内存,之后再通过增量同步写入同步期间增量的指令。如果同步较慢导致主节点buffer中内容被覆盖,则又要进行一次快照同步。因此需要设置一个合适大小的buffer。

无盘复制:主节点一边遍历内存,一边将序列化的内容发送到从节点。

wait指令确保强一致性

set key value
wait 5 0 #wait N t ,强制redis同步复制,5个从节点接受到数据时返回,否则无限等待t=0表示无限等待。

3.2、Sentinel(哨兵模式)

哨兵用于持续监测主节点和从节点,当有主节点发生异常时Sentinel会选出一个新的主节点,并将其他从节点与新的主节点建立复制关系。等旧的主节点恢复正常之后也成为其中一个从节点。

3.2.1、消息丢失问题

redis使用异步同步模式,当主节点挂了之后有可能数据没有同步到从节点,这时会发生数据丢失。

redis提供两个参数尽量避免数据丢失(不是一定能避免)。

min-slaves-to-write 1 #表示至少有一个从节点进行正常复制,否则就停止对外服务。
min-slaves-max-log 10 #表示10s内收到从节点的反馈,否则就是不正常。

第四章、拓展篇

4.1、Stream

Stream是redis的一种特殊数据结构,借鉴自Kafka。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hm3gAziR-1622899251415)(\images\redisStreamStructure.jpg)]

1、Stream支持多个消费组(Consumer Group),每个组有一个游标last_delivered_id。消费组中任意成员消费,游标向前移动(消息在同一个消息组被唯一消费)。

2、每个消息者内部会有一个状态变量pending_ids,记录已被读取但未接受到ack的消息。用于确保消息被成功消费。

 xadd msg * name sun #xadd key ID field string,*表示让redis自动生成ID
 xlen msg #获取消息长度
 xrange msg - + #xrange msg - +,获取消息列表,-表示最小值,+表示最大值

4.2 Info

info指令用于获取redis系统信息,分为9大块

info server XXX #服务器信息
info client XXX #客户端信息
info memory XXX #内存信息
info persistence XXX #持久化信息
info stats XXX #通用统计信息
info replication XXX #主从复制信息
info cpu XXX #cpu使用情况
info cluster XXX #集群信息
info keyspace XXX #键值对统计数量信息

使用info获取redis全部系统信息

info
# Server
redis_version:5.0.10
redis_git_sha1:1c047b68
redis_git_dirty:0
redis_build_id:76de97c74f6945e9
redis_mode:standalone
os:Windows
arch_bits:64
multiplexing_api:WinSock_IOCP
atomicvar_api:pthread-mutex
process_id:4576
run_id:db0774d7a59e46e7c063240ab37fdbae6b061ac9
tcp_port:6379
uptime_in_seconds:33
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:12033865
executable:D:\redis\redis-server.exe
config_file:D:\redis\redis.windows.conf

# Clients
connected_clients:1
client_recent_max_input_buffer:2
client_recent_max_output_buffer:0
blocked_clients:0

# Memory
used_memory:723808
used_memory_human:706.84K
used_memory_rss:681808
used_memory_rss_human:665.83K
used_memory_peak:723808
used_memory_peak_human:706.84K
used_memory_peak_perc:100.14%
used_memory_overhead:710510
used_memory_startup:660264
used_memory_dataset:13298
used_memory_dataset_perc:20.93%
allocator_allocated:39416784
allocator_active:511705088
allocator_resident:515899392
total_system_memory:0
total_system_memory_human:0B
used_memory_lua:37888
used_memory_lua_human:37.00K
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:12.98
allocator_frag_bytes:472288304
allocator_rss_ratio:1.01
allocator_rss_bytes:4194304
rss_overhead_ratio:0.00
rss_overhead_bytes:-515217584
mem_fragmentation_ratio:1.00
mem_fragmentation_bytes:0
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:49950
mem_aof_buffer:0
mem_allocator:jemalloc-5.2.1-redis
active_defrag_running:0
lazyfree_pending_objects:0

# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1622646568
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0

# Stats
total_connections_received:1
total_commands_processed:1
instantaneous_ops_per_sec:0
total_net_input_bytes:31
total_net_output_bytes:11483
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0

# Replication
role:master
connected_slaves:0
master_replid:3ecda06233f1018c4c582d35fb82da35607bf0de
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

# CPU
used_cpu_sys:0.109375
used_cpu_user:0.156250
used_cpu_sys_children:0.000000
used_cpu_user_children:0.000000

# Cluster
cluster_enabled:0

# Keyspace
db0:keys=5,expires=0,avg_ttl=0
redis-cli.exe info stats #获取通用统计数据

4.5、redis淘汰策略–LRU

当redis内存不足时提供一下几种策略用于内存回收。

  1. noviction:禁止写服务,允许读服务,能够有效防止数据丢失。
  2. volatile-lru:使用lru算法淘汰设置了过期时间的key。
  3. volatile-ttl:淘汰剩余过期时间最小的key。
  4. volatile-random:随机删除设置了过期时间的key。
  5. allkeys-lru:使用lru策略淘汰全体key,不光是设置了淘汰时间。
  6. allkeys-random:随机淘汰全体key中的一部分。

总结:volatie针对设置了过期时间的key,allkey针对全体key。

4.5.2、近似LRU算法

LRU算法需要记录每个key的最近访问频次,需要消耗大量内存空间,并且在每次访问时需要更新链表。

近似LRU算法为每个key设置一个最后一次被访问的时间戳(占24bit),当redis发现内存超出maxmemory时随机采样。删除样本中时间戳最早的,如果是allkeys策略,则随机删除一个key。

4.6、懒惰删除

redis del命令可用来删除redis对象,但如果一个key是一个特别大的对象,会造成redis的卡顿。

redis4.x版本引入了unlink命令,用于异步回收。

unlink key #等同于del key,异步回收资源
4.6.2、flush
flushall #删除当前db并持久化(rdb文件恢复到最初状态)
flushdb #删除当前db但不持久化(可以通过重启redis恢复)

4.7、Jedis

public class JedisTest{
    public static void main(String[] args){
        JedisPool pool = new JedisPool();//新建一个jedis连接池
        Jedis jedis = pool.getResource();//获取连接
        doSomething(jedis);//处理业务逻辑
        jedis.close();//关闭连接
    }
}

上述代码在业务逻辑发生异常时无法归还连接给连接池

public class JedisTest{
    public static void main(String[] args){
        JedisPool pool = new JedisPool();
        try(Jedis jedis = pool.getResource()){
            doSomething(jedis);
        }catch(Exception e){
            ...
        }
    }
}

上述代码会自动关闭try()中的资源,前提是这些资源实现了AutoCloseable接口。

上述代码还有问题,我们怎么保证所有程序员一定会这么写,从而确保jedis资源被释放。开发人员应该关注业务实现。因此需要对JedisPool再次封装。

public class JedisPool{
    private JedisPool pool = new JedisPool();
    
    public void excute(RedisCaller caller){
        try(Jedis jedis = pool.getResource()){
            caller.call(jedis);
        }
    }
}
public interface RedisCaller{
    public void call(Jedis jedis);
}

public class RedisTest{
    public static void main(String[] args){
		JedisPool pool = new JedisPool();
        pool.excute(new RedisCaller(){
            @Override
            public void call(Jedis jedis){
                jedis.doSomething();
            }
        })
    }
}

redis重试

我们只要在excute方法里进行重试即可

public class RetryJedisPool extends JedisPool{
    @Override
    public void excute(RedisCaller caller){
        try(Jedis jedis = pool.getResource()){
            caller.call(jedis);
        }catch(JedisConnectionException e){
            caller.call(jedis);
        }finnaly{
            jedis.close();
        }
    }
}

4.8、rename-command 指令

rename-command 指令用于将某些危险的指令修改成别的名称或禁用,比如flushall

rename-command flushall flushall-force #重命名
rename-command flushall "" #禁用flushall

4.9、spiped

redis本身不支持SSL连接,所以当redis数据在公网进行传输时有泄漏的风险。redis提供的方案时使用spiped。

原理时spiped会在客户端和服务端同时启动两个spiped进程,客户端先将数据发送给客户端spiped,再由客户端spiped将数据加密后发送给服务端spiped,服务端spiped将数据解密后发送给redis服务器。

{
jedis.doSomething();
}
})
}
}


redis重试

我们只要在excute方法里进行重试即可

```java
public class RetryJedisPool extends JedisPool{
    @Override
    public void excute(RedisCaller caller){
        try(Jedis jedis = pool.getResource()){
            caller.call(jedis);
        }catch(JedisConnectionException e){
            caller.call(jedis);
        }finnaly{
            jedis.close();
        }
    }
}

4.8、rename-command 指令

rename-command 指令用于将某些危险的指令修改成别的名称或禁用,比如flushall

rename-command flushall flushall-force #重命名
rename-command flushall "" #禁用flushall

4.9、spiped

redis本身不支持SSL连接,所以当redis数据在公网进行传输时有泄漏的风险。redis提供的方案时使用spiped。

原理时spiped会在客户端和服务端同时启动两个spiped进程,客户端先将数据发送给客户端spiped,再由客户端spiped将数据加密后发送给服务端spiped,服务端spiped将数据解密后发送给redis服务器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值