持久化

一、RDB 持久化

可以将 redis 在内存中的数据库状态保存到磁盘里面,避免数据因为服务器进程退出而丢失。

RDB 持久化既可以手动执行,也可以根据服务器配置选项定期执行,该功能可以将某个时间点上的数据库状态保存到一个 RDB 文件中。

RDB 持久化功能所生成的 RDB 文件是一个经过压缩的二进制文件。有 SAVE 和 BGSAVE 命令

  • SAVE 命令会阻塞 Redis 服务器进程,直到 RDB 文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求
查看更多

客户端和服务端

一、客户端

Redis 服务器状态结构的 clients 属性是一个链表,这个链表保存了所有与服务器连接的客户端的状态结构,对客户端执行批量操作,或者查找某个指定的客户端,都可以通过遍历 clients 链表来完成

1
2
3
4
5
struct redisServer {
...
// 一个链表,保存了所有客户端状态
list* clients;
}

而这个 clients 的每个节点指向的结构体如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct redisClient {
...
int fd;
robj* name;
int flags;
sds querybuf;
robj** argv;
int argc;
struct redisCommand* cmd;

char buf[REDIS_REPLY_CHUNK_BYTES];
int bufpos;

int authenticated;
}

查看更多

set命令

语法:

1
SET KEY value [EX seconds] [PX milliseconds] [NX | XX]

EX second:设置键的过期时间为 second 秒。SET KEY value EX second 效果等同于 SETEX KEY second value

PX millisecond:设置键的过期时间为 millisecond 毫秒。SET KEY value PX millisecond 效果等同于 PSETEX KEY millisecond value

查看更多

缓存穿透和雪崩

Redis 缓存穿透和雪崩

Redis 缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严重意义上讲,这个问题无解,如果对数据的一致性要求很高,那么就不能使用缓存。

另外的一些典型的问题就是:缓存穿透、缓存学霸和缓存击穿。目前,业界也都有比较流行的解决方案

一、缓存穿透(查不到导致的)

假如用户想要查询一个数据,发现Redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询,发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中(秒杀),于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现缓存穿透

解决方案:

1. 布隆过滤器

布隆过滤器是一种数据结构,对所有可能查询的参数以 hash 形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力;

查看更多

删除 DOcker 中已经停止的容器

删除 DOcker 中已经停止的容器

方法一:

1
2
3
4
5
# 显示所有的容器,过滤出 Exited 状态的容器,取出这些容器的 ID
sudo docker ps -a | grep Exited | awk '{print $1}'

# 查询所有的容器,过滤出 Exited 状态的容器,列出容器 ID,删除这些容器
sudo docker rm `docker ps -a | grep Exited | awk '{print $1}'`

方法二:

1
2
# 删除所有未运行的容器(已经运行的删除不了,未运行的就一起被删除了)
sudo docker rm $(sudo docker ps -a -q)

查看更多

底层实现原理

docker 虚拟化技术由这些技术支撑:namespace、Cgroups、union filesystem

一、Namespace

命名空间(namespace)是 linux 提供的用于隔离进程、网络、挂载点、进程间通信等资源的方法。docker 就是通过 linux 的 namespace 对不同的容器实现了隔离。

Linux 的命名空间机制提供了七种不同的命名空间,包括:clone_newcgroup、clone_newipc、clone_newnet、clone_newns、clone_newpid、clone_newuser、clone_newuts。通过这 7 个选项我们能在创建新的进程时,设置新进程应该在那些资源上与宿主机器进行隔离。

1. 进程隔离

进程 pid 隔离的实现,在使用 clone 系统调用创建一个新进程时,在参数中指定 CLONE_NEWPID 参数。新创建的这个进程将会 “看到” 一个全新的进程空间,在这个进程空间中,他的 pid 为 1。也就实现了针对进程 PID 的命名空间。在此命名空间中,看不到宿主机中真正的进程空间,也看不到其他命名空间的情况。

2. 网络隔离

3. 挂载点隔离

在新的进程中创建隔离的挂载点需要在 clone 系统调用中传入 CLONE_NEWNS

查看更多
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
输入一个整数数组 S:
数组长度 2 <= Length <= 1000000。
数组中每个元素取值范围在 0 <= Number <= 2^63 -1。

输入一个整数数组 S
请判断是否存在可能性把 S 的所有元素划分到两个非空子集 A 和 B,使得 SumA 是子集 A 中所有元素之和;SumB 是子集 B 中所有元素之和,且 SumA 和 SumB 同为奇数或者同为偶数。

示例:
S = [1,2,4,3,2,3,5,4]
如果 A = [1,2,3] SumA = 6,B = [4,2,3,5,4] SumB = 18
因此 S 可以划分成 SumA 和 SumB 都是偶数的两个子集 A 和 B。

实现函数解决这个问题,以 Go 语言为参考:
func HasPartition(numbers []int64) bool {
}

答案:
奇数的个数 如果是 “偶数个” 即可

红黑树和哈希表

一、红黑树和哈希表的对比

  • 时间复杂度: 红黑树增删改查的时间复杂度都是 O(logN),这个是相对稳定的,即使最差情况下,时间复杂度不会改变。哈希表增删改查的时间复杂度为 O(1)。并且查找速度和数据量大小基本无关。但是时间复杂度不太稳定,在插入或删除操作时,如果发生哈希冲突了,最坏的时间复杂度能达到 O(n)
  • 存储的数据是否有序:红黑树存储的数据有序,遍历时按照 key 的大小顺序排列。哈希表存储的数据无序。
  • 范围查找的效率:红黑树可以进行范围查找。哈希表想要范围查找的话,需要遍历整个哈希表。
  • 缓存利用率:红黑树较低,红黑树节点之间通过指针连接,可能存在不同的节点存储的不同的内存块,访问时缓存命中率低。哈希表因为存储在一个数组中,因此访问时缓存命中率高。
查看更多