Redis如何做持久化的?
bgsave做全量持久化到RDB二进制文件中,aof做增量持久化,存储的是文本协议数据。
它们的优缺点呢?
rdb二进制文件启动加载速度可以更快,aof要重放命令,所以速度比较慢
rdb,aof
RDB 快
浪费空间 消费性能 会丢失数据
AOF 备份稳健 默认取AOF得
占用空间 存在bug
RDB:Redis默认的持久化机制,将内存数据库快照保存在名字为 dump.rdb 的二进制文件中.RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储.[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
优点:(1)整个持久化文件只有一个,方便备份.(2)性能最大化,持久化采用fork子进程,避免了主进程的IO操作.(3).相比于AOF,持久化的数据加载快,启动效率高.
缺点:(1)在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失.(2)由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟
AOF:AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
优点:(1) 该机制可以带来更高的数据安全性,即数据持久性。(2). 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容.(3).AOF包含一个格式清晰,易于理解的日志文件用于记录所有的修改操作.
缺点:(1).AOF文件记录的所有操作过程,比rdb文件大,启动恢复速度比rdb慢.(2).根据同步策略的不同,AOF在运行效率上往往会慢于RDB.总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效.
Redis持久化期间,主进程还能对外提供服务吗?
能
那Redis如何处理新写入的数据呢,这个数据也会直接进行持久化吗?
。。。这个可能吧!
Reids可以设置最大内存大小,如果数据达到了内存最大限制,Redis如何处理呢?
可以配置淘汰策略 LRU 或者 LFU 淘汰策略。
Redis 的LRU算法实现原理,可以讲讲吗?
这个不太清楚。
图片
Redis 核心数据类型有哪些?
string, hash, list, set, zset.
存储数据用 string 类型 和 hash 类型,你是如何选择的呢?
string 对大量字段的对象中的某个数据进行获取,需要进行整体的数据获取,在客户端完成反序列化,而hash可以获取指定字段获取数据。所以根据访问需求来选择。
还有其他的考虑吗?
没有
zset 底层的实现原理有了解过吗?
1.有序集合对象的编码可以是ziplist或者skiplist。同时满足以下条件时使用ziplist编码:
元素数量小于128个
所有member的长度都小于64字节
其他:
不能满足上面两个条件的使用 skiplist 编码。以上两个条件也可以通过Redis配置文件zset-max-ziplist-entries 选项和 zset-max-ziplist-value 进行修改
对于一个 REDIS_ENCODING_ZIPLIST 编码的 Zset, 只要满足以上任一条件, 则会被转换为 REDIS_ENCODING_SKIPLIST 编码
skiplist 编码的 Zset 底层为一个被称为 zset 的结构体,这个结构体中包含一个字典和一个跳跃表。跳跃表按 score 从小到大保存所有集合元素,查找时间复杂度为平均
O(logN),最坏 O(N
。字典则保存着从 member 到 score 的映射,这样就可以用 O(1) 的复杂度来查找 member 对应的 score 值。虽然同时使用两种结构,但它们会通过指针来共享相同元素的 member 和 score,因此不会浪费额外的内存。
你能讲讲它的实现原理以及时间复杂度分析吗?
这个不太清楚。
图片
你能说说缓存穿透是怎么回事吗?
缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。
解决方案:
(一)利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试
(二)采用异步更新策略,无论key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。
(三)提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的Key是否合法有效。如果不合法,则直接返回。
可以用布隆过滤器来阻挡。
布隆过滤器的实现原理是什么?能讲讲么?
AtomicInteger+CAS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
public class BloomFilter implements Serializable{ private final int[] seeds; private final int size; private final BitSet notebook; private final MisjudgmentRate rate; private final AtomicInteger useCount = new AtomicInteger(); private final Double autoClearRate; public BloomFilter(int dataCount){ this(MisjudgmentRate.MIDDLE, dataCount, null); } public BloomFilter(MisjudgmentRate rate, int dataCount, Double autoClearRate){ long bitSize = rate.seeds.length * dataCount; if(bitSize<0 || bitSize>Integer.MAX_VALUE){ throw new RuntimeException("位数太大溢出了,请降低误判率或者降低数据大小"); } this.rate = rate; seeds = rate.seeds; size = (int)bitSize; notebook = new BitSet(size); this.autoClearRate = autoClearRate; } public boolean addIfNotExist(String data){ checkNeedClear(); int[] indexs = new int[seeds.length]; boolean exist = true; int index; for(int i=0; i<seeds.length; i++){ indexs[i] = index = hash(data, seeds[i]); if(exist){ if(!notebook.get(index)){ exist = false; for(int j=0; j<=i; j++){ setTrue(indexs[j]); } } }else{ setTrue(index); } } return exist; } private int hash(String data, int seeds) { char[] value = data.toCharArray(); int hash = 0; if(value.length>0){ for(int i=0; i<value.length; i++){ hash = i * hash + value[i]; } } hash = hash * seeds % size; return Math.abs(hash); } private void setTrue(int index) { useCount.incrementAndGet(); notebook.set(index, true); } private void checkNeedClear() { if(autoClearRate != null){ if(getUseRate() >= autoClearRate){ synchronized (this) { if(getUseRate() >= autoClearRate){ notebook.clear(); useCount.set(0); } } } } } private Double getUseRate() { return (double)useCount.intValue()/(double)size; } public void saveFilterToFile(String path) { try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path))) { oos.writeObject(this); } catch (Exception e) { throw new RuntimeException(e); } } public static BloomFilter readFilterFromFile(String path) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path))) { return (BloomFilter) ois.readObject(); } catch (Exception e) { throw new RuntimeException(e); } }
public void clear() { useCount.set(0); notebook.clear(); } public MisjudgmentRate getRate() { return rate; }
public enum MisjudgmentRate {
VERY_SMALL(new int[] { 2, 3, 5, 7 }),
SMALL(new int[] { 2, 3, 5, 7, 11, 13, 17, 19 }),
MIDDLE(new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53 }),
HIGH(new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131 }); private int[] seeds; private MisjudgmentRate(int[] seeds) { this.seeds = seeds; } public int[] getSeeds() { return seeds; } public void setSeeds(int[] seeds) { this.seeds = seeds; } } public static void main(String[] args) { BloomFilter fileter = new BloomFilter(7); System.out.println(fileter.addIfNotExist("1111111111111")); System.out.println(fileter.addIfNotExist("2222222222222222")); System.out.println(fileter.addIfNotExist("3333333333333333")); System.out.println(fileter.addIfNotExist("444444444444444")); System.out.println(fileter.addIfNotExist("5555555555555")); System.out.println(fileter.addIfNotExist("6666666666666")); System.out.println(fileter.addIfNotExist("1111111111111")); System.out.println(fileter.getUseRate()); System.out.println(fileter.addIfNotExist("1111111111111")); } }
|