diff --git a/cache/README.md b/cache/README.md index da922ec..0305586 100644 --- a/cache/README.md +++ b/cache/README.md @@ -29,21 +29,21 @@ 3. B 更新缓存,缓存中数据被更新为2 4. A 更新缓存,缓存中数据被更新为1 5. 此时缓存中数据为1,而DB中数据为2。这种不一致会一直持续到缓存过期,或者缓存和DB再次被更新,并且被修改正确; -![](img/db_before_cache.png) +![](./img/db_before_cache.png) 1. 先更新缓存,再更新 DB。不一致的情况; 1. A 更新缓存,缓存中数据被更新为1 2. B 更新缓存,缓存中数据被更新为2 3. B 更新 DB,DB中数据被更新为2 4. A 更新 DB,DB中数据被更新为1 5. 此时缓存中数据为2,但是DB 中数据为1。这种不一致会一直持续到缓存过期,或者缓存和DB再次被更新,并且被修改正确; -![](img/cache_before_db.png) +![](./img/cache_before_db.png) 1. 先更新 DB,再删除缓存。不一致的情况; 1. A 从数据库中读取数据1 2. B 更新数据库为2 3. B 删除缓存 4. A 更新缓存为1 5. 此时缓存中数据为1,数据库中数据为2 -![](img/db_remove_cache.png) +![](./img/db_remove_cache.png) 所以本质上,没有完美的解决方案,或者说仅仅考虑这种更新顺序,是不足以解决缓存一致性问题的。 diff --git a/database/transaction.md b/database/transaction.md index 6240a92..1e8ca23 100644 --- a/database/transaction.md +++ b/database/transaction.md @@ -13,7 +13,7 @@ innodb 引擎是通过MVCC来支持事务的。(到这一步,停下来,接 关键点:ACID,innodb 通过 MVCC 支持事务 -![数据库事务](img/transaction.png) +![数据库事务](./img/transaction.png) ## 扩展点 @@ -86,7 +86,7 @@ InnoDB 作为一个优等生,在[隔离级别定义](https://en.wikipedia.org/ - 对于仅包含连续相同当前读语句的事务,第一个当前读会加临键锁,会阻塞别的事物的修改,也避免了幻读。 - 但是对于快照都和当前读语句交错的事务,第一个快照读后其它事务仍可以修改并提交内容,当前事务的后续当前读就会读到其他事务带来的变更。导致可以造出一些印证 InnoDB 没有解决幻读问题的例子。 -![](img/rr-phantom-read-example.png) +![](./img/rr-phantom-read-example.png) #### 参考资料 @@ -129,7 +129,7 @@ InnoDB 作为一个优等生,在[隔离级别定义](https://en.wikipedia.org/ 2. 间隙锁:锁住记录之间的间隔,或者索引之前的范围,或者所以之后的范围。只在重复读级别产生,(可以在前面隔离级别的地方提) 3. 临键锁(Next key lock):记录锁和间隙锁的组合,即锁住记录,又锁住了间隙 -![记录锁和间隙锁](img/next_key_lock.png) +![记录锁和间隙锁](./img/next_key_lock.png) ### innodb 引擎和 MyISAM 引擎的区别 diff --git a/golang/mutex.md b/golang/mutex.md index b22f99a..6a44b06 100644 --- a/golang/mutex.md +++ b/golang/mutex.md @@ -8,14 +8,14 @@ 在大多数的锁实现里面——不仅仅是 Go 的 mutex 都是有套路的: -![](img/lock_pattern.png) +![](./img/lock_pattern.png) 所以基本上就是两步: - 自旋加锁,所谓的自旋也就是 CAS 操作,将锁从无锁状态修改为加锁状态。自旋这个过程一般可以可通过控制自旋的次数或者时长来控制; - 自旋失败之后就进入队列,等待释放锁的时候被唤醒; 但是 Go 有一点特殊,即 Go 有所谓的正常模式和饥饿模式。为了理解这个问题,要先看这么一个问题: -![](img/lock_competition_two_ways.png) +![](./img/lock_competition_two_ways.png) 如果锁此时已经被释放了,那么你作为一个设计者,你会把锁给谁? diff --git a/microservice/timeout.md b/microservice/timeout.md index 52379ed..995b8e6 100644 --- a/microservice/timeout.md +++ b/microservice/timeout.md @@ -75,7 +75,7 @@ 首先我们看一个例子: -![链路超时](img/chain-timeout.png) +![链路超时](./img/chain-timeout.png) 基本步骤是: - 客户端最开始的时候,链路超时时间是 3s。一般在 BFF 里面会设置好整个链路的超时时间,而后逐步传递; diff --git a/mq/Kafka.md b/mq/Kafka.md index a8d1c18..d9293ac 100644 --- a/mq/Kafka.md +++ b/mq/Kafka.md @@ -2,7 +2,7 @@ 分析: 如果只是宽泛地谈 Kafka,那么回答的点就要围绕 Kafka 的几个组成来。这个部分不必谈及“为什么 Kafka 高性能” “为什么 Kafka 高可用”等问题。因为按照一般的惯例,接下来就会聊这个话题。总跳回答的思路就是介绍一下 Kafka 的基本原理,几个主要概念。后面详细的内容,等后面面试官来提问。 -![Kafka知识点](img/kafka_available_performance.png) +![Kafka知识点](./img/kafka_available_performance.png) 答:Kafka 是一个基于发布订阅模式的消息队列中间件。它由 Producer, Consumer, Broker 和 Partition 几个组成。 diff --git a/mq/README.md b/mq/README.md index 7186f3c..cb64c77 100644 --- a/mq/README.md +++ b/mq/README.md @@ -2,7 +2,7 @@ 分析:如果不考察特定的消息中间件,那么就是考察一般的消息队列的理论。 -![消息队列概览](img/mq_overview.jpeg) +![消息队列概览](./img/mq_overview.jpeg) 基本上就是围绕以上这些考点。因为不考察具体的消息中间件的原理,反而不太好回答,因为这些问题都是要在实际中遇到过,才能有比较深刻的体会。所以下面的很多回答,都是使用了我自己的例子,读者要进行相应的替换,提前准备好。 @@ -22,7 +22,7 @@ 关键字:**一致性**,**幂等**,**顺序** -![大概模式](img/overview.jpeg) +![大概模式](./img/overview.jpeg) ## 问题 @@ -40,8 +40,8 @@ 关键字:**解耦**,**异步**,**削峰** -![直接调用](img/decouple1.jpeg) -![依赖中间件解耦](img/decouple2.jpeg) +![直接调用](./img/decouple1.jpeg) +![依赖中间件解耦](./img/decouple2.jpeg) #### 类似问题 @@ -89,7 +89,7 @@ 分析:这个问题有别于“如何保证消息只会发送一次”。消息消费幂等,意味着发送方可能发送了多次,或者消费中间出了什么问题,导致了重复消费。单纯的消息中间件并不能保证。例如,当网络超时的时候,中间件完全不知道,消费者消费了没有,成功还是失败。如果不重试,那么就可能没消费;如果重试,就可能重复消费。这里有些人可能会回答`ACK`机制,其实这是不对的,`ACK`机制并不能保证幂等。因为你`ACK`了,你并不能确保中间件一定能收到。看后面**什么情况导致重复消费**。 -![ACK 机制无法确保幂等性](img/ack_timeout.jpeg) +![ACK 机制无法确保幂等性](./img/ack_timeout.jpeg) 答案:保证幂等性,主要依赖消费者自己去完成。一般来说,一条消息里面都会带上标记这一次业务的某些特征字段。核心就是利用这些字段来去重。比如说,最常见的是利用数据库的唯一索引来去重,要小心的就是,采用 `check - doSomething` 模式可能会有并发问题。 @@ -205,7 +205,7 @@ 分析:消息积压,核心就在于生产者太快而消费者太慢。解决思路要么控制生产者的发送速率,要么提高消费者的效率。一般我们不太会倾向于控制发送者的速率,所以解决问题的思路就变成了如何提高消费者效率。提高消费者的效率,要么提高消费单条消息的效率,要么是增加消费者的数量。 -![消息积压解决思路](img/too_many_msg.jpeg) +![消息积压解决思路](./img/too_many_msg.jpeg) 答案:整体上有两个思路: diff --git a/redis/availability.md b/redis/availability.md index a8bd58c..7c8ff42 100644 --- a/redis/availability.md +++ b/redis/availability.md @@ -10,7 +10,7 @@ Redis Sentinel 模式要注意有两个集群,一个是存放了 Redis 数据的集群,一个是监控这个数据集群的哨兵集群。于是就需要理解哨兵集群之间是如何监控的,如何就某件事达成协议,以及哨兵自身的容错。 -![Redis 高可用](img/availability.png) +![Redis 高可用](./img/availability.png) 答案:Redis 高可用有两种模式,Sentinel 和 Cluster。 diff --git a/redis/data_structure.md b/redis/data_structure.md index c40a1d3..2e1b5f5 100644 --- a/redis/data_structure.md +++ b/redis/data_structure.md @@ -2,9 +2,9 @@ 分析:这是`Redis`必考题。考察`Redis`数据结构有两大类问法,一种是直接问你某种数据结构的特征,一种是问你某个场景下应该使用什么数据结构。本质上,两者考察的都是同一个东西,即你是否了解某种数据结构。在复习这个模块的时候,要从表象和底层实现两个角度去学习,熟记于心。你要注意区分,你要回答的是 Redis 值对象的数据结构(表象),还是底层实现。大多数情况下,你应该从表象出发,即值对象的角度出发,而后讨论每一种值对象的可能的底层实现。如果记不住全部的底层实现,可以只讨论重点的几个。先看图: -![值对象](img/value_object.png) +![值对象](./img/value_object.png) -![底层数据结构](img/data_structure.png) +![底层数据结构](./img/data_structure.png) 总体回答的讨论就是“某种值对象-有什么实现-某种实现的特点”。 diff --git a/redis/expired.md b/redis/expired.md index dd70d7c..ee085d0 100644 --- a/redis/expired.md +++ b/redis/expired.md @@ -2,7 +2,7 @@ 分析:Redis 对过期键值对的处理,可以说是日经题。核心就是懒惰删除+定期删除。前者很容易记忆,后者很容易忽略。而要刷亮点,要从 RDB, AOF 和 主从复制三个不同处理策略上着手。 -![过期策略](img/expired.png) +![过期策略](./img/expired.png) 答案: Redis 删除过期键值对,主要依赖于两种方式,定期删除和懒惰删除。 diff --git a/redis/io_model.md b/redis/io_model.md index edfd1e7..0ae730c 100644 --- a/redis/io_model.md +++ b/redis/io_model.md @@ -2,7 +2,7 @@ 分析:所有的 IO 模型,考来考去就是一句话,**IO多路复用**。因为操作系统就那么一回事,你要高性能,就没啥选择,反正别问,问就是`IO 多路复用`。那么为什么大家还问呢?因为`IO 多路复用`大体上大家都是差不多的,但是细节上就五花八门。回答 Redis 的 IO 模型,亮点可以从两个角度刷,一个是和`memcache`的比较;一个是从 6.0 支持多线程角度刷。 -![IO 模型](img/io_model.png) +![IO 模型](./img/io_model.png) 核心就是四个组件。 diff --git a/redis/persistent.md b/redis/persistent.md index 6ef243a..25c99be 100644 --- a/redis/persistent.md +++ b/redis/persistent.md @@ -4,7 +4,7 @@ 进一步,我们可以拿 Redis 的 AOF 机制和 MySQL 的 `binlog` 进行对比,它们都记录的是中间执行步骤。而 MySQL 的`mysqldump`就非常接近 `RDB`,也是一种快照保存方案。 -![Redis 持久化](img/persistence.png) +![Redis 持久化](./img/persistence.png) 答案: Redis 的持久化机制分成两种,RDB 和 AOF。