From be667815cb58d699eb83b69359038b0205c2f607 Mon Sep 17 00:00:00 2001 From: tink Date: Wed, 5 Jun 2024 01:54:44 +0800 Subject: [PATCH] update --- docs/computer-system/io.md | 29 ++++- docs/database/redis/redis.md | 69 ++++++++++- docs/qa/dist.md | 8 +- docs/qa/mysql.md | 27 +++-- docs/qa/queue.md | 24 ++-- site/computer-system/io/index.html | 88 ++++++++++++-- site/database/redis/redis/index.html | 174 ++++++++++++++++++++++++++- site/qa/dist/index.html | 8 +- site/qa/mysql/index.html | 79 ++++++++---- site/qa/queue/index.html | 33 ++--- site/search/search_index.json | 2 +- site/sitemap.xml | 82 ++++++------- site/sitemap.xml.gz | Bin 557 -> 557 bytes 13 files changed, 487 insertions(+), 136 deletions(-) diff --git a/docs/computer-system/io.md b/docs/computer-system/io.md index 78d535c..268d94e 100644 --- a/docs/computer-system/io.md +++ b/docs/computer-system/io.md @@ -144,13 +144,14 @@ Linux下Buffered IO默认使用的是Write back机制,即文件操作的写只 ### 1.2 进程上下文切换(进程切换)   为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换(也叫调度)。因此可以说,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。 -  从一个进程的运行转到另一个进程上运行,这个过程中经过下面这些变化: -1. 保存当前进程A的上下文。 +从一个进程的运行转到另一个进程上运行,这个过程中经过下面这些变化: -  上下文就是内核再次唤醒当前进程时所需要的状态,由一些对象(程序计数器、状态寄存器、用户栈等各种内核数据结构)的值组成。 +1. 保存当前进程A的上下文 + + 上下文就是内核再次唤醒当前进程时所需要的状态,由一些对象(程序计数器、状态寄存器、用户栈等各种内核数据结构)的值组成。 + + 这些值包括描绘地址空间的页表、包含进程相关信息的进程表、文件表等。 -  这些值包括描绘地址空间的页表、包含进程相关信息的进程表、文件表等。 -   2. 切换页全局目录以安装一个新的地址空间。 3. 恢复进程B的上下文。 @@ -185,6 +186,7 @@ write过程中会有很多次拷贝,直到数据全部写到磁盘。 2. 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process) 正式因为这两个阶段,linux系统产生了下面五种网络模式的方案: + - 阻塞 I/O(blocking IO) - 非阻塞 I/O(nonblocking IO) - I/O 多路复用( IO multiplexing) @@ -308,6 +310,23 @@ select/epoll的优势并不是对于单个连接能处理得更快,而是在 - 而asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了他人(kernel)完成,然后他人做完后发信号通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。 +## Epoll模式 + +### Epoll支持的两种操作模式 + +epoll对文件描述符有两种操作模式 + +- LT(Level Trigger水平模式) + + LT是epoll的默认操作模式,当epoll_wait函数检测到有事件发生并将通知应用程序,而应用程序不一定必须立即进行处理,这样epoll_wait函数再次检测到此事件的时候还会通知应用程序,直到事件被处理。LT支持阻塞的套接字和非阻塞的套接字。 + +- ET(Edge Trigger边缘模式) + + ET模式下,只要epoll_wait函数检测到事件发生,通知应用程序立即进行处理,后续的epoll_wait函数将不再检测此事件。因此ET模式在很大程度上降低了同一个事件被epoll触发的次数,因此效率比LT模式高。ET只支持非阻塞的套接字。 + +**ET是状态变化的通知,即从没有数据转到有数据会通知,LT是数据变化的通知,即有数据就通知,没数据就不通知**。对于ET模式,当接收到通知后,应该一直read循环读取,直到返回EWOULDBLOCK或EAGAIN,这样内部状态才会从有数据再次转为无数据,从而为下一次数据的到来做准备,否则只有对端再次发送数据时候,才会再次触发可读事件。 + +对于ET状态应该注意防止恶意请求连接,防止其一直请求,造成其他请求饿死。 ## 资料 diff --git a/docs/database/redis/redis.md b/docs/database/redis/redis.md index 078eb3a..215df72 100644 --- a/docs/database/redis/redis.md +++ b/docs/database/redis/redis.md @@ -3,12 +3,15 @@ ## redis架构 - 纯内存操作 -- 单线程避免了多线程频繁的上小文切换问题 +- 单线程避免了多线程因为同步导致的频繁的上下文切换问题 - 高效的数据结构 -- 核心是基于非阻塞的IO多路复用 +- 核心是基于非阻塞的IO多路复用(epoll) ## 应用场景 +![](https://static.cyub.vip/images/202406/redis-case.jpg) + +- 缓存 - 队列 - 排行榜 - 自动补全 @@ -251,6 +254,66 @@ info commandstats info keyspace ``` +## 基于Redis实现分布式锁的几种方案 + +基于Redis实现分布式锁的缺点: + +1. 超时时间不好设置 + + 当线程A获取到锁之后,可能业务还没有执行完成,锁就过期了 + +2. 锁可能无法永远无法释放 +3. 锁可靠性问题 + + 1. 对于redis cluster集群,当线程A刚获取到锁后,此时锁所在Master节点恰好挂了,数据还没同步到Slave节点,而Slave节点恰好升级为主节点,导致B线程可以获取到锁。此时A、B线程同时在执行业务 + + 2. 线程A执行完成任务后,去释放锁,可能是否释放掉了其他线程持有的锁(比如线程A执行完成时候,锁早已过期,线程B获取到了锁) + +### SETNX + EXPIRE + +如果执行完setnx加锁,正要执行expire设置过期时间时,进程crash或redis挂掉了,会到锁永远无法释放。 + +### SETNX + value值是(系统时间+过期时间) + +可以把过期时间放到setnx的value值里面。如果加锁成功,再拿出value值校验一下是否过期即可。 + +### 使用Lua脚本(包含SETNX + EXPIRE两条指令) + +### SET的扩展命令(SET EX PX NX) + +> SET key value[EX seconds][PX milliseconds][NX|XX] + +- NX :表示key不存在的时候,才能set成功,也即保证只有第一个客户端请求才能获得锁,而其他客户端请求只能等其释放锁,才能获取。 +- EX seconds :设定key的过期时间,时间单位是秒。 +- PX milliseconds: 设定key的过期时间,单位为毫秒 +- XX: 仅当key存在时设置值 + +XX可以设置当前线程关联的值,当要释放锁时候,判断当前所锁的关联的值是否是当前线程关联的值,如果是才允许释放,这解决了3.b问题。可以通过Lua脚本保证这个过程的原子性: + +```lua +if redis.call('get',KEYS[1]) == ARGV[1] then + return redis.call('del',KEYS[1]) +else + return 0 +end; +``` + +### Redisson + +给获得锁的线程,开启一个定时守护线程,每隔一段时间检查锁是否还存在,存在则对锁的过期时间延长,防止锁过期提前释放。这解决了问题1。 + +当前开源框架Redisson解决了这个问题。Redisson底层原理如下: + +![](https://static.cyub.vip/images/202406/redisson.webp) + +### Redlock + +对于3.a问题,Redis作者 antirez提出一种高级的分布式锁算法:Redlock。Redlock核心思想如下: + +> 当一个客户端要获取红锁时,它会尝试在多个 Redis 节点上分别执行 SETNX(SET if Not eXists)命令,如果大多数(N/2+1)加锁成功了,则认为获取锁成功。 + + ## 资料 -- [Redis---持久化方式RDB、AOF](https://blog.csdn.net/zhangpower1993/article/details/89034941) \ No newline at end of file +- [Redis---持久化方式RDB、AOF](https://blog.csdn.net/zhangpower1993/article/details/89034941) +- [七种方案!探讨Redis分布式锁的正确使用姿势](https://juejin.cn/post/6936956908007850014) \ No newline at end of file diff --git a/docs/qa/dist.md b/docs/qa/dist.md index 00cd0c1..37d200f 100644 --- a/docs/qa/dist.md +++ b/docs/qa/dist.md @@ -18,7 +18,7 @@ 假定有几台Redis服务器,假定是N,要存储key-value数据,传统模式是根据hash(key)%N服务器数量来定位出来存放在第几台服务器上面。 -一致性Hash算法,会使用2^32个虚拟hash槽位,可以想象成在一个圆环(也叫hash环)上面有0到2^32-1编号的槽位。首先我们确定每台Redis服务器在这个环上槽位,可以用服务器IP或ID或者name进行hash: +一致性Hash算法,会使用2\^32个虚拟hash槽位,可以想象成在一个圆环(也叫hash环)上面有0到2\^32-1编号的槽位。首先我们确定每台Redis服务器在这个环上槽位,可以用服务器IP或ID或者name进行hash: > 槽位 = hash(Redis服务器IP)%2^32 当一个key-value数据过来时候,根据key计算出其在环上槽位,然后沿着环顺时针行走,遇到的第一个服务器就是要存放的服务器。 @@ -64,7 +64,7 @@ Cap理论中C代表一致性,A代表可用性,P代表分区容忍性。CAP ## 什么是Raft算法? -Raft算法属于强一致性算法实现。在Raft中,每个节点在同一时刻只能处于以下三种状态之一: +Raft算法属于最终一致性致性算法实现。在Raft中,每个节点在同一时刻只能处于以下三种状态之一: - 领导者(Leader) - 候选者(Candidate) @@ -224,11 +224,11 @@ saga保证满足以下业务规则: ## Consul架构是怎么样的? -![](https://learn.hashicorp.com/assets/images/consul-arch.png?ynotemdtimestamp=1627634261331) +![](https://static.cyub.vip/images/202406/consul-arch.png) - Agent是Consul集群中的守护进程。它的生命周期从启动Consul agent开始。Agent可以以client或是server模式运行 -- Client:Client是转发所有RPC请求道Server的Agent。Client相对来说是无状态的,它的唯一后台活动是参与LAN gossip pool。它的资源开销很小,只消耗少量的网络带宽 +- Client:Client是转发所有RPC请求到Server的Agent。Client相对来说是无状态的,它的唯一后台活动是参与LAN gossip pool。它的资源开销很小,只消耗少量的网络带宽 - Server:Server是负责参与Raft quorum,维护集群状态,响应RPC查询,和其他datacenter交换WAN gossip信息并转发查询到leader或是远程datacenter的Agent diff --git a/docs/qa/mysql.md b/docs/qa/mysql.md index 2a07bf6..223b05d 100644 --- a/docs/qa/mysql.md +++ b/docs/qa/mysql.md @@ -297,7 +297,7 @@ slow log用来记录慢查询 ## 查询语句不同元素(where、jion、limit、group by、having等等)执行先后顺序? -where字句在聚合前先筛选记录,也就是说作用在group by和having字句前。而 having子句在聚合后对组记录进行筛选。 +where在聚合前先筛选记录,也就是说作用在group by和having之前。而 having子句在聚合后对组记录进行筛选。 ## Innodb为什么一定需要一个主键,且必须自增列作为主键? @@ -306,14 +306,14 @@ where字句在聚合前先筛选记录,也就是说作用在group by和having 总之Innodb一定需要一个主键。 1. 这是因为数据记录本身被存于主索引(一颗B+Tree)的叶子节点上,这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放 -2. 如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页(这样的页称为叶子页) +2. 如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页(这样的页称为叶子页) 3. 如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新记录都要被插到现有索引页得中间某个位置 ## 在MVCC并发控制中,读操作可以分成哪两类? -快照读 (snapshot read):读取的是记录的可见版本 (有可能是历史版本),不用加锁(共享读锁s锁也不加,所以不会阻塞其他事务的写)。 +**快照读 (snapshot read)**:读取的是记录的可见版本 (有可能是历史版本),不用加锁(共享读锁s锁也不加,所以不会阻塞其他事务的写)。 -当前读 (current read):读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。 +**当前读 (current read)**:读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。 ## Mysql中DATATIME和TIMESTAP的区别? @@ -323,13 +323,15 @@ datetime、timestamp精确度都是秒,datetime与时区无关,存储的范 - 事务隔离级别设置为SERIALIZABLE 串行化 - MVCC + Next-Key Lock - Next-Key Lock是Gap Lock(间隙锁)和Record Lock(行锁)的结合版,都属于Innodb的锁机制。 - 比如:select * from tb where id>100 for update: + Next-Key Lock(临键锁) 是Gap Lock(间隙锁)和Record Lock(记录锁,属于行锁)的结合版,都属于Innodb的锁机制。 比如:select * from tb where id>100 for update: + 1. 主键索引 id 会给 id=100 的记录加上 record行锁 2. 索引 id 上会加上 gap 锁,锁住 id(100,+无穷大)这个范围,其他事务对 id>100 范围的记录读和写操作都将被阻塞。插入 id=1000的记录时候会命中索引上加的锁会报出事务异常; - Next-Key Lock会确定一段范围,然后对这个范围加锁,保证A在where的条件下读到的数据是一致的,因为在where这个范围其他事务根本插不了也删不了数据,都被Next-Key Lock锁堵在一边阻塞掉了。 + 3. Next-Key Lock会确定一段范围,然后对这个范围加锁,保证A在where的条件下读到的数据是一致的,因为在where这个范围其他事务根本插不了也删不了数据,都被Next-Key Lock锁堵在一边阻塞掉了。 + +> 记录锁是行级别的锁(row-level locks),当InnoDB 对索引进行搜索或扫描时,会在索引对应的记录上设置共享或排他的记录锁。 ## Mysql什么时候会取得gap lock或nextkey lock? @@ -504,7 +506,7 @@ KEY分区跟HASH分区类似,分区字段可以是除text和BLOB外的所有 ## 索引名字规则 -``` +```sql idx(a, b, c) HIT where a = x and b = x idx(a, b, c) HIT where a > x idx(a, b, c) Not HIT where b > x @@ -520,7 +522,8 @@ idx(a, b, c) Not HIT where a = x group by b ``` mysql建立多列索引(联合索引)有最左前缀的原则,即最左优先,如: -- 如果有一个2列的索引(col1,col2),则已经对(col1)、(col1,col2)上建立了索引; + +- 如果有一个2列的索引(col1,col2),则已经对(col1)、(col1,col2)上建立了索引; - 如果有一个3列索引(col1,col2,col3),则已经对(col1)、(col1,col2)、(col1,col2,col3)上建立了索引; @@ -542,4 +545,8 @@ b+ 树的数据项是复合的数据结构,比如 (name,age,sex) 的时候,b ## mysql中悲观锁、乐观锁、共享锁、排他锁有什么区别? -![](https://static.cyub.vip/images/202107/mysql-lock.jpg) \ No newline at end of file +![](https://static.cyub.vip/images/202107/mysql-lock.jpg) + +## 更多资料 + +- [MySQL记录锁、间隙锁、临键锁(Next-Key Locks)详解](https://blog.csdn.net/yzx3105/article/details/129675468) \ No newline at end of file diff --git a/docs/qa/queue.md b/docs/qa/queue.md index fae264c..bf81c8b 100644 --- a/docs/qa/queue.md +++ b/docs/qa/queue.md @@ -26,7 +26,7 @@ Kafka是高吞吐低延迟的高并发、高性能的消息中间件,配置良 自 Kafka 2.4 之后,Kafka 提供了有限度的读写分离,也就是说,Follower 副本能够对外提供读服务。 1. 业务场景不适用。读写分离适用于那种读负载很大,而写操作相对不频繁的场景,可 Kafka 不属于这样的场景。 -2. 同步机制。Kafka 采用 PULL 方式实现 Follower 的同步,因此,Follower 与 Leader 存 在不一致性窗口。如果允许读 Follower 副本,就势必要处理消息滞后(Lagging)的问题。 +2. 同步机制。Kafka 采用 PULL 方式实现 Follower 的同步,因此Follower 与 Leader 存 在不一致性窗口。如果允许读 Follower 副本,就势必要处理消息滞后(Lagging)的问题。 ## 如何解决kafka消息重复消费问题? @@ -36,7 +36,7 @@ Kafka是高吞吐低延迟的高并发、高性能的消息中间件,配置良 ## Kafka消息是采用Pull模式,还是Push模式? -kafka遵循了一种大部分消息系统共同的传统的设计:producer将消息推送到broker,consumer从broker拉取消息。同redis的bpop命令类似,Kafka有个参数可以让consumer阻塞知道新消息到达,可以防止consumer不断在循环中轮询。 +kafka遵循了一种大部分消息系统共同的传统的设计:producer将消息推送(push)到broker,consumer从broker拉取(pull)消息。同redis的bpop命令类似,Kafka有个参数可以让consumer阻塞知道新消息到达,可以防止consumer不断在循环中轮询。 ## kafka中如何防止消息丢失? @@ -45,9 +45,11 @@ Kafka消息发送有两种方式:同步(sync)和异步(async),默认 - 0 表示producer不等待来自broker同步完成的确认继续发送下一条消息; + - 1 表示producer在leader已成功收到的数据并得到确认后发送下一条message,默认状态 + - -1 表示producer在header,follower副本确认接收到数据后才算一次发送完成; @@ -107,23 +109,21 @@ Kafka 副本当前分为领导者副本和追随者副本。只有 Leader 副本 message delivery semantic 也就是消息传递语义。通用的概念,也就是消息传递过程中消息传递的保证性。分为三种: -- 最多一次(at most once) - - 消息可能丢失也可能被处理,但最多只会被处理一次。 +- **最多一次(at most once)** - 可能丢失 不会重复 + 消息可能丢失也可能被处理,但最多只会被处理一次。可能丢失,不会重复。 -- 至少一次(at least once) + **只管发送,不管对方收没收到。** - 消息不会丢失,但可能被处理多次。 +- **至少一次(at least once)** - 可能重复 不会丢失 + 消息不会丢失,但可能被处理多次。可能重复 不会丢失。 -- 精确传递一次(exactly once) + **发送之后,会等待对方确认之后才会停止发送。** - 消息被处理且只会被处理一次。 +- **精确传递一次(exactly once)** - 不丢失 不重复 就一次 + 消息被处理且只会被处理一次。不丢失,不重复,就一次。 ## 介绍一下beanstalk? diff --git a/site/computer-system/io/index.html b/site/computer-system/io/index.html index d2f1702..6a4d57d 100644 --- a/site/computer-system/io/index.html +++ b/site/computer-system/io/index.html @@ -630,6 +630,26 @@ + + +
  • + + Epoll模式 + + + +
  • @@ -1841,6 +1861,26 @@ +
  • + +
  • + + Epoll模式 + + + +
  • @@ -1972,14 +2012,19 @@ $ dd if=/dev/urandom of=sync.txt bs=64M count=16 iflag=fullblock oflag=sync

    补充:地址空间就是一个非负整数地址的有序集合。如{0,1,2...}。

    1.2 进程上下文切换(进程切换)

    为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换(也叫调度)。因此可以说,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。

    -

    从一个进程的运行转到另一个进程上运行,这个过程中经过下面这些变化: -1. 保存当前进程A的上下文。

    -

    上下文就是内核再次唤醒当前进程时所需要的状态,由一些对象(程序计数器、状态寄存器、用户栈等各种内核数据结构)的值组成。

    -

    这些值包括描绘地址空间的页表、包含进程相关信息的进程表、文件表等。 -   -2. 切换页全局目录以安装一个新的地址空间。

    +

    从一个进程的运行转到另一个进程上运行,这个过程中经过下面这些变化:

      -
    1. 恢复进程B的上下文。
    2. +
    3. +

      保存当前进程A的上下文

      +

      上下文就是内核再次唤醒当前进程时所需要的状态,由一些对象(程序计数器、状态寄存器、用户栈等各种内核数据结构)的值组成。

      +

      这些值包括描绘地址空间的页表、包含进程相关信息的进程表、文件表等。

      +
    4. +
    5. +

      切换页全局目录以安装一个新的地址空间。

      +
    6. +
    7. +

      恢复进程B的上下文。

      +

    可以理解成一个比较耗资源的过程。   

    @@ -1998,12 +2043,14 @@ $ dd if=/dev/urandom of=sync.txt bs=64M count=16 iflag=fullblock oflag=sync

    对于一次IO访问(这回以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的缓冲区,最后交给进程。所以说,当一个read操作发生时,它会经历两个阶段: 1. 等待数据准备 (Waiting for the data to be ready) 2. 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)

    -

    正式因为这两个阶段,linux系统产生了下面五种网络模式的方案: -- 阻塞 I/O(blocking IO) -- 非阻塞 I/O(nonblocking IO) -- I/O 多路复用( IO multiplexing) -- 信号驱动 I/O( signal driven IO) -- 异步 I/O(asynchronous IO)

    +

    正式因为这两个阶段,linux系统产生了下面五种网络模式的方案:

    +

    block I/O模型(阻塞I/O)

    阻塞I/O模型示意图:

    @@ -2119,6 +2166,21 @@ $ dd if=/dev/urandom of=sync.txt bs=64M count=16 iflag=fullblock oflag=sync

    而asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了他人(kernel)完成,然后他人做完后发信号通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。

  • +

    Epoll模式

    +

    Epoll支持的两种操作模式

    +

    epoll对文件描述符有两种操作模式

    + +

    ET是状态变化的通知,即从没有数据转到有数据会通知,LT是数据变化的通知,即有数据就通知,没数据就不通知。对于ET模式,当接收到通知后,应该一直read循环读取,直到返回EWOULDBLOCK或EAGAIN,这样内部状态才会从有数据再次转为无数据,从而为下一次数据的到来做准备,否则只有对端再次发送数据时候,才会再次触发可读事件。

    +

    对于ET状态应该注意防止恶意请求连接,防止其一直请求,造成其他请求饿死。

    资料

    + + +
  • + + 基于Redis实现分布式锁的几种方案 + + + +
  • @@ -1761,6 +1816,61 @@ +
  • + +
  • + + 基于Redis实现分布式锁的几种方案 + + + +
  • @@ -1789,12 +1899,14 @@

    redis架构

    应用场景

    +

    什么是Raft算法?

    -

    Raft算法属于强一致性算法实现。在Raft中,每个节点在同一时刻只能处于以下三种状态之一:

    +

    Raft算法属于最终一致性致性算法实现。在Raft中,每个节点在同一时刻只能处于以下三种状态之一:

    Consul架构是怎么样的?

    -

    +

    @@ -2304,6 +2311,13 @@ mysql中悲观锁、乐观锁、共享锁、排他锁有什么区别? +
  • + +
  • + + 更多资料 + +
  • @@ -2650,33 +2664,40 @@ InnoDB MVCC的实现基于undo log,通过回滚指针来构建需要的版本

    slow log

    slow log用来记录慢查询

    查询语句不同元素(where、jion、limit、group by、having等等)执行先后顺序?

    -

    where字句在聚合前先筛选记录,也就是说作用在group by和having字句前。而 having子句在聚合后对组记录进行筛选。

    +

    where在聚合前先筛选记录,也就是说作用在group by和having之前。而 having子句在聚合后对组记录进行筛选。

    Innodb为什么一定需要一个主键,且必须自增列作为主键?

    如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引。如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引。如果也没有这样的唯一索引,则InnoDB会选择内置6字节长的ROWID作为隐含的聚集索引(ROWID随着行记录的写入而主键递增,这个ROWID不像ORACLE的ROWID那样可引用,是隐含的)。

    总之Innodb一定需要一个主键。

    1. 这是因为数据记录本身被存于主索引(一颗B+Tree)的叶子节点上,这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放
    2. -
    3. 如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页(这样的页称为叶子页)
    4. +
    5. 如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页(这样的页称为叶子页)
    6. 如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新记录都要被插到现有索引页得中间某个位置

    在MVCC并发控制中,读操作可以分成哪两类?

    -

    快照读 (snapshot read):读取的是记录的可见版本 (有可能是历史版本),不用加锁(共享读锁s锁也不加,所以不会阻塞其他事务的写)。

    -

    当前读 (current read):读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。

    +

    快照读 (snapshot read):读取的是记录的可见版本 (有可能是历史版本),不用加锁(共享读锁s锁也不加,所以不会阻塞其他事务的写)。

    +

    当前读 (current read):读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。

    Mysql中DATATIME和TIMESTAP的区别?

    datetime、timestamp精确度都是秒,datetime与时区无关,存储的范围广(1001-9999),占空间8个字节,timestamp与时区有关,查询时候会转换成相应时区显示,存储的范围小(1970-2038),占用空间4个字节。

    MySQL是如何解决幻读的?

    +
    +

    记录锁是行级别的锁(row-level locks),当InnoDB 对索引进行搜索或扫描时,会在索引对应的记录上设置共享或排他的记录锁。

    +

    Mysql什么时候会取得gap lock或nextkey lock?