Skip to content

Commit b8e9ee6

Browse files
committed
更新Redis基础知识
1 parent cca80d8 commit b8e9ee6

File tree

2 files changed

+145
-103
lines changed

2 files changed

+145
-103
lines changed

Java/Java基础.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,92 @@ public class OuterClass {
287287
### final
288288

289289
1. **基本数据**类型用final修饰,则不能修改,是常量;**对象引用**用final修饰,则引用只能指向该对象,不能指向别的对象,但是对象本身可以修改。
290+
290291
2. final修饰的方法不能被子类重写
292+
291293
3. final修饰的类不能被继承。
292294

295+
296+
297+
### this
298+
299+
`this.属性名称`指访问类中的成员变量,可以用来区分成员变量和局部变量。如下代码所示,`this.name`访问类Person当前实例的变量。
300+
301+
```java
302+
/**
303+
* @description:
304+
* @author: 程序员大彬
305+
* @time: 2021-08-17 00:29
306+
*/
307+
public class Person {
308+
String name;
309+
int age;
310+
311+
public Person(String name, int age) {
312+
this.name = name;
313+
this.age = age;
314+
}
315+
}
316+
```
317+
318+
`this.方法名称`用来访问本类的方法。以下代码中,`this.born()`调用类 Person 的当前实例的方法。
319+
320+
```java
321+
/**
322+
* @description:
323+
* @author: 程序员大彬
324+
* @time: 2021-08-17 00:29
325+
*/
326+
public class Person {
327+
String name;
328+
int age;
329+
330+
public Person(String name, int age) {
331+
this.born();
332+
this.name = name;
333+
this.age = age;
334+
}
335+
336+
void born() {
337+
}
338+
}
339+
```
340+
341+
342+
343+
### super
344+
345+
super 关键字用于在子类中访问父类的变量和方法。
346+
347+
```java
348+
class A {
349+
protected String name = "大彬";
350+
351+
public void getName() {
352+
System.out.println("父类:" + name);
353+
}
354+
}
355+
356+
public class B extends A {
357+
@Override
358+
public void getName() {
359+
System.out.println(super.name);
360+
super.getName();
361+
}
362+
363+
public static void main(String[] args) {
364+
B b = new B();
365+
b.getName();
366+
}
367+
/**
368+
* 大彬
369+
* 父类:大彬
370+
*/
371+
}
372+
```
373+
374+
在子类B中,我们重写了父类的getName()方法,如果在重写的getName()方法中我们要调用父类的相同方法,必须要通过super关键字显式指出。
375+
293376
## object常用方法
294377

295378
Java面试经常会出现的一道题目,Object的常用方法。下面给大家整理一下。

中间件/Redis入门指南总结.md

Lines changed: 62 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969

7070
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
7171

72+
目录结构如下:
73+
74+
![](https://gitee.com/tysondai/img/raw/master/image-20210914000822843.png)
7275

7376
## 简介
7477

@@ -84,29 +87,11 @@ Redis是一个高性能的key-value数据库。Redis对数据的操作都是原
8487
4. 支持持久化。Redis支持RDB和AOF两种持久化机制,持久化功能有效地避免数据丢失问题。
8588
5. redis 采用IO多路复用技术。多路指的是多个socket连接,复用指的是复用一个线程。redis使用单线程来轮询描述符,将数据库的开、关、读、写都转换成了事件。多路复用主要有三种技术:select,poll,epoll。epoll是最新的也是目前最好的多路复用技术。
8689

87-
缺点:
88-
89-
对join或其他结构化查询的支持就比较差
90-
91-
非关系型数据库适用场景:
92-
93-
1. 数据高并发的读写
94-
2. 海量数据的读写
95-
3. 对扩展性要求高的数据
96-
97-
关系型数据库适用场景:
98-
99-
1. 存储结构化数据,如用户的帐号、地址。
100-
2. 数据需要做结构化查询,复杂查询
101-
3. 要求事务性、一致性
90+
缺点:对join或其他结构化查询的支持就比较差。
10291

10392
### io多路复用
10493

105-
阻塞io:当你调用read时,如果没有数据收到,那么线程或者进程就会被挂起,直到收到数据。
106-
107-
将用户socket对应的文件描述符(file description)注册进epoll,然后epoll帮你监听哪些socket上有消息到达。当某个socket可读或者可写的时候,它可以给你一个通知。只有当系统通知我哪个描述符可读了,我才去执行read操作,可以保证每次read都能读到有效数据而不做纯返回-1和EAGAIN的无用功。
108-
109-
这样,多个描述符的I/O操作都能在一个线程内并发交替地顺序完成,这就叫I/O多路复用,这里的“复用”指的是复用同一个线程。
94+
将用户socket对应的文件描述符(file description)注册进epoll,然后epoll帮你监听哪些socket上有消息到达。当某个socket可读或者可写的时候,它可以给你一个通知。只有当系统通知哪个描述符可读了,才去执行read操作,可以保证每次read都能读到有效数据。这样,多个描述符的I/O操作都能在一个线程内并发交替地顺序完成,这就叫I/O多路复用,这里的复用指的是复用同一个线程。
11095

11196
### 应用场景
11297

@@ -116,34 +101,12 @@ Redis是一个高性能的key-value数据库。Redis对数据的操作都是原
116101
4. 好友关系,利用集合的一些命令,比如求交集、并集、差集等。可以方便搞定一些共同好友、共同爱好之类的功能。
117102
5. 限速器,比较典型的使用场景是限制某个用户访问某个API的频率,常用的有抢购时,防止用户疯狂点击带来不必要的压力。
118103

119-
![](../img/middleware/redis-usage.png)
120-
121-
### Memcached
122-
123-
与redis区别:
104+
### Memcached和Redis的区别
124105

125106
1. Redis只使用单核,而Memcached可以使用多核。
126107
2. MemCached数据结构单一,仅用来缓存数据,而Redis支持更加丰富的数据类型,也可以在服务器端直接对数据进行丰富的操作,这样可以减少网络IO次数和数据体积。
127108
3. MemCached不支持数据持久化,断电或重启后数据消失。Redis支持数据持久化和数据恢复,允许单点故障。
128109

129-
### 启动与停止
130-
131-
**启动**
132-
133-
切换目录到redis下,运行:
134-
`redis-server redis.windows.conf`
135-
136-
若配置了环境变量,可直接运行`redis-server`
137-
138-
新打开一个窗口,切换到redis目录下并运行(配置了环境变量可直接运行)
139-
`redis-cli -h 127.0.0.1 -p 6379`
140-
141-
>Linux下通过配置文件redis.conf设置deamonize yes允许后台进程,开启redis-server后控制台仍然可以接收输入。requirepass可以设置密码。
142-
143-
**停止**
144-
145-
`redis-cli SHUTDOWN`
146-
147110

148111

149112
## 数据类型
@@ -540,7 +503,7 @@ ziplist是 Redis 为了节约内存而开发的, 由一系列特殊编码的
540503
- 最底层的链表包含所有的元素
541504
- 跳跃表的查找次数近似于层数,时间复杂度为O(logn),插入、删除也为 O(logn)
542505

543-
![](../img/redis/redis-skiplist.png)
506+
![](https://gitee.com/tysondai/img/raw/master/redis-skiplist.png)
544507

545508
#### 对象
546509

@@ -582,7 +545,7 @@ hash类型内部编码有两种:
582545

583546
Redis3.2版本提供了quicklist内部编码,简单地说它是以一个ziplist为节点的linkedlist,它结合了ziplist和linkedlist两者的优势,为列表类型提供了一种更为优秀的内部编码实现。
584547

585-
![image-20201018203457076](../img/redis/list-api.png)
548+
![](https://gitee.com/tysondai/img/raw/master/list-api.png)
586549

587550
使用场景:
588551

@@ -667,7 +630,7 @@ GET #返回文章ID。
667630

668631
3. EXEC命令进行提交事务
669632

670-
![事务](https://img-blog.csdnimg.cn/20190125175715521.jpg)
633+
![](https://gitee.com/tysondai/img/raw/master/redis-multi.jpg)
671634

672635
DISCARD:放弃事务,即该事务内的所有命令都将取消
673636

@@ -690,7 +653,7 @@ QUEUED
690653

691654
事务里的命令执行时会读取最新的值:
692655

693-
![](../img/middleware/redis-transaction.png)
656+
![](https://gitee.com/tysondai/img/raw/master/redis-transaction.png)
694657

695658
### WATCH命令
696659

@@ -837,7 +800,7 @@ SLAVEOF NO ONE //停止接收其他数据库的同步并转化为主数据库。
837800
5. 同步数据集。第一次同步的时候,从数据库启动后会向主数据库发送SYNC命令。主数据库接收到命令后开始在后台保存快照(RDB持久化过程),并将保存快照过程接收到的命令缓存起来。当快照完成后,Redis会将快照文件和缓存的命令发送到从数据库。从数据库接收到后,会载入快照文件并执行缓存的命令。以上过程称为复制初始化。
838801
6. 复制初始化完成后,主数据库每次收到写命令就会将命令同步给从数据库,从而实现主从数据库数据的一致性。
839802

840-
![image-20201031160722595](../img/redis/redis-replication.png)
803+
![](https://gitee.com/tysondai/img/raw/master/redis-replication.png)
841804

842805
Redis在2.8及以上版本使用psync命令完成主从数据同步,同步过程分为:全量复制和部分复制。
843806

@@ -936,8 +899,6 @@ Redis集群内节点通过ping/pong消息实现节点通信,消息不但可以
936899

937900

938901

939-
940-
941902
## LUA脚本
942903

943904
Redis 通过 LUA 脚本创建具有原子性的命令: 当lua脚本命令正在运行的时候,不会有其他脚本或 Redis 命令被执行,实现组合命令的原子操作。
@@ -971,7 +932,7 @@ redis 127.0.0.1:6379> EVALSHA "232fd51614574cf0867b83d384a5e898cfd24e5a" 0
971932

972933
使用evalsha执行Lua脚本过程如下:
973934

974-
![image-20201024233130770](E:/project/java/learn/Java-learning/img/redis/evalsha.png)
935+
![](https://gitee.com/tysondai/img/raw/master/evalsha.png)
975936

976937
### lua脚本作用
977938

@@ -1008,56 +969,6 @@ RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.cla
1008969
Number count = redisTemplate.execute(redisScript, keys, limit.count(), limit.period());
1009970
```
1010971

1011-
1012-
1013-
## pipeline
1014-
1015-
redis客户端执行一条命令分4个过程: 发送命令-〉命令排队-〉命令执行-〉返回结果。使用Pipeline可以批量请求,批量返回结果,执行速度比逐条执行要快。
1016-
1017-
使用pipeline组装的命令个数不能太多,不然数据量过大,增加客户端的等待时间,还可能造成网络阻塞,可以将大量命令的拆分多个小的pipeline命令完成。
1018-
1019-
原生批命令(mset, mget)与Pipeline对比:
1020-
1021-
1. 原生批命令是原子性,pipeline是非原子性。pipeline命令中途异常退出,之前执行成功的命令不会回滚。
1022-
1023-
2. 原生批命令只有一个命令, 但pipeline支持多命令。
1024-
1025-
1026-
1027-
## 数据一致性
1028-
1029-
缓存和DB之间怎么保证数据一致性:
1030-
读操作:先读缓存,缓存没有的话读DB,然后取出数据放入缓存,最后响应数据
1031-
写操作:先删除缓存,再更新DB
1032-
为什么是删除缓存而不是更新缓存呢?
1033-
1034-
1. 线程安全问题。同时有请求A和请求B进行更新操作,那么会出现(1)线程A更新了缓存(2)线程B更新了缓存(3)线程B更新了数据库(4)线程A更新了数据库,由于网络等原因,请求B先更新数据库,这就导致缓存和数据库不一致的问题。
1035-
2. 如果业务需求写数据库场景比较多,而读数据场景比较少,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。
1036-
3. 如果你写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。
1037-
1038-
先删除缓存,再更新DB,同样也有问题。假如A先删除了缓存,但还没更新DB,这时B过来请求数据,发现缓存没有,去请求DB拿到旧数据,然后再写到缓存,等A更新完了DB之后就会出现缓存和DB数据不一致的情况了。
1039-
1040-
解决方法:采用延时双删策略。更新完数据库之后,延时一段时间,再次删除缓存,确保可以删除读请求造成的缓存脏数据。评估项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上,加几百ms即可。
1041-
1042-
```java
1043-
public void write(String key,Object data){
1044-
redis.delKey(key);
1045-
db.updateData(data);
1046-
Thread.sleep(1000);//确保读请求结束,写请求可以删除读请求造成的缓存脏数据
1047-
redis.delKey(key);
1048-
}
1049-
```
1050-
1051-
可以将第二次删除作为异步的。自己起一个线程,异步删除。这样,写的请求就不用沉睡一段时间后了,加大吞吐量。
1052-
1053-
当删缓存失败时,也会就出现数据不一致的情况。
1054-
1055-
解决方法:
1056-
1057-
![](../img/redis/cache-consist.png)
1058-
1059-
1060-
1061972
## 删除策略
1062973

1063974
1. 被动删除。在访问key时,如果发现key已经过期,那么会将key删除。
@@ -1084,7 +995,9 @@ public void write(String key,Object data){
1084995

1085996

1086997

1087-
## 客户端
998+
## 其他
999+
1000+
### 客户端
10881001

10891002
Redis 客户端与服务端之间的通信协议是在TCP协议之上构建的。
10901003

@@ -1099,7 +1012,7 @@ OK
10991012

11001013

11011014

1102-
## 慢查询
1015+
### 慢查询
11031016

11041017
Redis原生提供慢查询统计功能,执行`slowlog get{n}`命令可以获取最近的n条慢查询命令,默认对于执行超过10毫秒的命令都会记录到一个定长队列中,线上实例建议设置为1毫秒便于及时发现毫秒级以上的命令。慢查询队列长度默认128,可适当调大。
11051018

@@ -1120,3 +1033,49 @@ slowlog reset //重置,清理列表
11201033
1. 修改为低时间复杂度的命令,如hgetall改为hmget等,禁用keys、sort等命令。
11211034
2. 调整大对象:缩减大对象数据或把大对象拆分为多个小对象,防止一次命令操作过多的数据。
11221035

1036+
### pipeline
1037+
1038+
redis客户端执行一条命令分4个过程: 发送命令-〉命令排队-〉命令执行-〉返回结果。使用Pipeline可以批量请求,批量返回结果,执行速度比逐条执行要快。
1039+
1040+
使用pipeline组装的命令个数不能太多,不然数据量过大,增加客户端的等待时间,还可能造成网络阻塞,可以将大量命令的拆分多个小的pipeline命令完成。
1041+
1042+
原生批命令(mset, mget)与Pipeline对比:
1043+
1044+
1. 原生批命令是原子性,pipeline是非原子性。pipeline命令中途异常退出,之前执行成功的命令不会回滚。
1045+
1046+
2. 原生批命令只有一个命令, 但pipeline支持多命令。
1047+
1048+
### 数据一致性
1049+
1050+
缓存和DB之间怎么保证数据一致性:
1051+
读操作:先读缓存,缓存没有的话读DB,然后取出数据放入缓存,最后响应数据
1052+
写操作:先删除缓存,再更新DB
1053+
为什么是删除缓存而不是更新缓存呢?
1054+
1055+
1. 线程安全问题。同时有请求A和请求B进行更新操作,那么会出现(1)线程A更新了缓存(2)线程B更新了缓存(3)线程B更新了数据库(4)线程A更新了数据库,由于网络等原因,请求B先更新数据库,这就导致缓存和数据库不一致的问题。
1056+
2. 如果业务需求写数据库场景比较多,而读数据场景比较少,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。
1057+
3. 如果你写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。
1058+
1059+
先删除缓存,再更新DB,同样也有问题。假如A先删除了缓存,但还没更新DB,这时B过来请求数据,发现缓存没有,去请求DB拿到旧数据,然后再写到缓存,等A更新完了DB之后就会出现缓存和DB数据不一致的情况了。
1060+
1061+
解决方法:采用延时双删策略。更新完数据库之后,延时一段时间,再次删除缓存,确保可以删除读请求造成的缓存脏数据。评估项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上,加几百ms即可。
1062+
1063+
```java
1064+
public void write(String key,Object data){
1065+
redis.delKey(key);
1066+
db.updateData(data);
1067+
Thread.sleep(1000);//确保读请求结束,写请求可以删除读请求造成的缓存脏数据
1068+
redis.delKey(key);
1069+
}
1070+
```
1071+
1072+
可以将第二次删除作为异步的。自己起一个线程,异步删除。这样,写的请求就不用沉睡一段时间后了,加大吞吐量。
1073+
1074+
当删缓存失败时,也会就出现数据不一致的情况。
1075+
1076+
解决方法:
1077+
1078+
![](https://gitee.com/tysondai/img/raw/master/image-20210913235221410.png)
1079+
1080+
> 图片来源:https://tech.it168.com
1081+

0 commit comments

Comments
 (0)