doc: 阅读redis sentinel文档
This commit is contained in:
346
http/http3.md
346
http/http3.md
@@ -1,173 +1,173 @@
|
|||||||
- [HTTP3 \& QUIC Protocols](#http3--quic-protocols)
|
- [HTTP3 \& QUIC Protocols](#http3--quic-protocols)
|
||||||
- [What is HTTP3](#what-is-http3)
|
- [What is HTTP3](#what-is-http3)
|
||||||
- [TCP/IP模型中HTTP3 vs QUIC](#tcpip模型中http3-vs-quic)
|
- [TCP/IP模型中HTTP3 vs QUIC](#tcpip模型中http3-vs-quic)
|
||||||
- [QUIC Protocol](#quic-protocol)
|
- [QUIC Protocol](#quic-protocol)
|
||||||
- [What is QUIC Used For](#what-is-quic-used-for)
|
- [What is QUIC Used For](#what-is-quic-used-for)
|
||||||
- [HTTP/1.1 vs HTTP/2 vs HTTP/3: Main differences](#http11-vs-http2-vs-http3-main-differences)
|
- [HTTP/1.1 vs HTTP/2 vs HTTP/3: Main differences](#http11-vs-http2-vs-http3-main-differences)
|
||||||
- [Best Features of HTTP/3 and QUIC](#best-features-of-http3-and-quic)
|
- [Best Features of HTTP/3 and QUIC](#best-features-of-http3-and-quic)
|
||||||
- [QUIC handshake](#quic-handshake)
|
- [QUIC handshake](#quic-handshake)
|
||||||
- [0-RTT on Prior Connections](#0-rtt-on-prior-connections)
|
- [0-RTT on Prior Connections](#0-rtt-on-prior-connections)
|
||||||
- [Head-of-Line Blocking Removal](#head-of-line-blocking-removal)
|
- [Head-of-Line Blocking Removal](#head-of-line-blocking-removal)
|
||||||
- [HOL blocking术语](#hol-blocking术语)
|
- [HOL blocking术语](#hol-blocking术语)
|
||||||
- [How does QUIC remove head-of-line blocking](#how-does-quic-remove-head-of-line-blocking)
|
- [How does QUIC remove head-of-line blocking](#how-does-quic-remove-head-of-line-blocking)
|
||||||
- [Flexible Bandwidth Management](#flexible-bandwidth-management)
|
- [Flexible Bandwidth Management](#flexible-bandwidth-management)
|
||||||
- [Pre-Stream Flow Control](#pre-stream-flow-control)
|
- [Pre-Stream Flow Control](#pre-stream-flow-control)
|
||||||
- [拥塞控制算法](#拥塞控制算法)
|
- [拥塞控制算法](#拥塞控制算法)
|
||||||
|
|
||||||
|
|
||||||
# HTTP3 & QUIC Protocols
|
# HTTP3 & QUIC Protocols
|
||||||
http3旨在通过QUIC(下一代传输层协议)来令网站更快、更安全。
|
http3旨在通过QUIC(下一代传输层协议)来令网站更快、更安全。
|
||||||
|
|
||||||
在协议高层,http3提供了和http2相同的功能,例如header compression和stream优先级控制。然而,在协议底层,QUIC传输层协议彻底修改了web传输数据的方式。
|
在协议高层,http3提供了和http2相同的功能,例如header compression和stream优先级控制。然而,在协议底层,QUIC传输层协议彻底修改了web传输数据的方式。
|
||||||
|
|
||||||
## What is HTTP3
|
## What is HTTP3
|
||||||
HTTP是一个应用层的网络传输协议,定义了client和server之间的request-reponse机制,允许client/server发送和接收HTML文档和其他文本、meidia files。
|
HTTP是一个应用层的网络传输协议,定义了client和server之间的request-reponse机制,允许client/server发送和接收HTML文档和其他文本、meidia files。
|
||||||
|
|
||||||
http3最初被称为`HTTP-over-QUIC`,其主要目标是令http语法及现存的http/2功能能够和QUIC传输协议兼容。
|
http3最初被称为`HTTP-over-QUIC`,其主要目标是令http语法及现存的http/2功能能够和QUIC传输协议兼容。
|
||||||
|
|
||||||
故而,`HTTP/3`的所有新特性都来源于QUIC层,包括内置加密、新型加密握手、对先前的连接进行zero round-trip恢复,消除头部阻塞问题以及原生多路复用。
|
故而,`HTTP/3`的所有新特性都来源于QUIC层,包括内置加密、新型加密握手、对先前的连接进行zero round-trip恢复,消除头部阻塞问题以及原生多路复用。
|
||||||
|
|
||||||
## TCP/IP模型中HTTP3 vs QUIC
|
## TCP/IP模型中HTTP3 vs QUIC
|
||||||
通过internet传输信息是复杂的操作,涉及到软件和硬件层面。由于不同的设备、工具、软件都拥有不同的特性,故而单一协议无法描述完整的通信流程。
|
通过internet传输信息是复杂的操作,涉及到软件和硬件层面。由于不同的设备、工具、软件都拥有不同的特性,故而单一协议无法描述完整的通信流程。
|
||||||
|
|
||||||
故而,网络通信是已于通信的协议栈实现的,协议栈中每一层职责都不同。为了使用网络系统来通信,host必须实现构成互联网协议套件的一系列分层协议集。通常,主机至少为每层实现一个协议。
|
故而,网络通信是已于通信的协议栈实现的,协议栈中每一层职责都不同。为了使用网络系统来通信,host必须实现构成互联网协议套件的一系列分层协议集。通常,主机至少为每层实现一个协议。
|
||||||
|
|
||||||
而HTTP则是应用层协议,令web server和web browser之间可以相互通信。http消息(request/reponse)在互联网中则是通过传输层协议来进行传递:
|
而HTTP则是应用层协议,令web server和web browser之间可以相互通信。http消息(request/reponse)在互联网中则是通过传输层协议来进行传递:
|
||||||
- 在http/2和http/1.1中,通过TCP协议来进行传递
|
- 在http/2和http/1.1中,通过TCP协议来进行传递
|
||||||
- 在`http/3`中,则是通过QUIC协议来进行传递
|
- 在`http/3`中,则是通过QUIC协议来进行传递
|
||||||
|
|
||||||
> `QUIC`为http/3新基于的传输层协议,之前http都基于tcp协议进行传输
|
> `QUIC`为http/3新基于的传输层协议,之前http都基于tcp协议进行传输
|
||||||
|
|
||||||
## QUIC Protocol
|
## QUIC Protocol
|
||||||
`QUIC`协议是一个通用的传输层协议,其可以和任意兼容的应用层协议来一起使用,HTTP/3是QUIC的最新用例。
|
`QUIC`协议是一个通用的传输层协议,其可以和任意兼容的应用层协议来一起使用,HTTP/3是QUIC的最新用例。
|
||||||
|
|
||||||
`QUIC`协议基于`UDP`协议构建,其负责server和client之间应用数据的物理传输。UDP协议是一个简单、轻量的协议,其传输速度高但是缺失可靠性、安全性等特性。QUIC实现了这些高层的传输特性,故而可以用于优化http数据通过网络的传输。
|
`QUIC`协议基于`UDP`协议构建,其负责server和client之间应用数据的物理传输。UDP协议是一个简单、轻量的协议,其传输速度高但是缺失可靠性、安全性等特性。QUIC实现了这些高层的传输特性,故而可以用于优化http数据通过网络的传输。
|
||||||
|
|
||||||
在HTTP/3中,HTTP的连接从`TCP-based`迁移到了`UDP-based`,底层的网络通信结构都发生了变化。
|
在HTTP/3中,HTTP的连接从`TCP-based`迁移到了`UDP-based`,底层的网络通信结构都发生了变化。
|
||||||
|
|
||||||
### What is QUIC Used For
|
### What is QUIC Used For
|
||||||
QUIC其创建是同于代替`TCP`协议的,QUIC作为传输层协议,相比于TCP更加灵活,性能问题更少。QUIC协议继承了安全传输的特性,并且拥有更快的adoption rate。
|
QUIC其创建是同于代替`TCP`协议的,QUIC作为传输层协议,相比于TCP更加灵活,性能问题更少。QUIC协议继承了安全传输的特性,并且拥有更快的adoption rate。
|
||||||
|
|
||||||
QUIC协议底层基于UDP协议的原因是`大多数设备只支持TCP和UDP的端口号`。
|
QUIC协议底层基于UDP协议的原因是`大多数设备只支持TCP和UDP的端口号`。
|
||||||
|
|
||||||
除此之外,`QUIC`还利用了UDP的如下特性:
|
除此之外,`QUIC`还利用了UDP的如下特性:
|
||||||
- UDP的connectionless特性可以使其将多路复用下移到传输层,并且基于UDP的QUIC实现并不会和TCP协议一样存在头部阻塞的问题
|
- UDP的connectionless特性可以使其将多路复用下移到传输层,并且基于UDP的QUIC实现并不会和TCP协议一样存在头部阻塞的问题
|
||||||
- UDP的间接性能够令QUIC重新实现TCP的可靠性和带宽管理功能
|
- UDP的间接性能够令QUIC重新实现TCP的可靠性和带宽管理功能
|
||||||
|
|
||||||
基于QUIC协议的传输和TCP相比是完全不同的方案:
|
基于QUIC协议的传输和TCP相比是完全不同的方案:
|
||||||
- 在底层,其是无连接的,其底层基于UDP协议
|
- 在底层,其是无连接的,其底层基于UDP协议
|
||||||
- 在高层,其是`connection-oriented`的,其在高层重新实现了TCP协议中连接建立、loss detection等特性,从而确保了数据的可靠传输
|
- 在高层,其是`connection-oriented`的,其在高层重新实现了TCP协议中连接建立、loss detection等特性,从而确保了数据的可靠传输
|
||||||
|
|
||||||
综上,QUIC协议结合了UDP和TCP两种协议的优点。
|
综上,QUIC协议结合了UDP和TCP两种协议的优点。
|
||||||
|
|
||||||
除了上述优点外,QUIC还`在传输层实现了高级别的安全性`。QUIC集成了`TLS 1.3`协议中的大部分特性,令其和自身的传输机制相兼容。在`HTTP/3` stack中,encryption并非是可选的,而是内置特性。
|
除了上述优点外,QUIC还`在传输层实现了高级别的安全性`。QUIC集成了`TLS 1.3`协议中的大部分特性,令其和自身的传输机制相兼容。在`HTTP/3` stack中,encryption并非是可选的,而是内置特性。
|
||||||
|
|
||||||
TCP, UDP, QUIC协议的相互比较如下:
|
TCP, UDP, QUIC协议的相互比较如下:
|
||||||
| | TCP | UDP | QUIC |
|
| | TCP | UDP | QUIC |
|
||||||
| :-: | :-: | :-: | :-: |
|
| :-: | :-: | :-: | :-: |
|
||||||
Layer in the TCP/IP model | transport | transport | transport |
|
Layer in the TCP/IP model | transport | transport | transport |
|
||||||
| place in the TCP/IP model | on top of ipv4/ipv6 | on top of ipv4/ipv6 | on top of UDP |
|
| place in the TCP/IP model | on top of ipv4/ipv6 | on top of ipv4/ipv6 | on top of UDP |
|
||||||
| connection type | connection-oriented | connectionless | connection-oriented |
|
| connection type | connection-oriented | connectionless | connection-oriented |
|
||||||
| order of delivery | in-order delivery | out-of-order delivery | out-of-order delivery between streams, in order delivery within stremas |
|
| order of delivery | in-order delivery | out-of-order delivery | out-of-order delivery between streams, in order delivery within stremas |
|
||||||
| guarantee of delivery | guaranteed | no guarantee of delivery | guaranteed |
|
| guarantee of delivery | guaranteed | no guarantee of delivery | guaranteed |
|
||||||
| security | unencrypted | unencrypted | encrypted |
|
| security | unencrypted | unencrypted | encrypted |
|
||||||
| data identification | knows nothing about the data it transports | knows nothing about the data it transports | use stream IDs to identify the independent streams it transports |
|
| data identification | knows nothing about the data it transports | knows nothing about the data it transports | use stream IDs to identify the independent streams it transports |
|
||||||
|
|
||||||
## HTTP/1.1 vs HTTP/2 vs HTTP/3: Main differences
|
## HTTP/1.1 vs HTTP/2 vs HTTP/3: Main differences
|
||||||
H3除了在底层协议栈传输层中引入QUIC和UDP协议外,还存在其他改动,具体如图所示:
|
H3除了在底层协议栈传输层中引入QUIC和UDP协议外,还存在其他改动,具体如图所示:
|
||||||
<img loading="lazy" alt="Comparison of the HTTP/1.1 vs HTTP/2 vs HTTP/3 protocol stacks" src="https://www.debugbear.com/assets/images/http11-2-3-comparison-88d3a12d6cc3f5422c3700a7f2f8c76b.jpg" width="1526" height="926" style="border-radius:4px" data-abc="true" class="img_CujE">
|
<img loading="lazy" alt="Comparison of the HTTP/1.1 vs HTTP/2 vs HTTP/3 protocol stacks" src="https://www.debugbear.com/assets/images/http11-2-3-comparison-88d3a12d6cc3f5422c3700a7f2f8c76b.jpg" width="1526" height="926" style="border-radius:4px" data-abc="true" class="img_CujE">
|
||||||
|
|
||||||
HTTP/3-QUIC-UDP stack和TCP-based版本的HTTP最重要的区别如下:
|
HTTP/3-QUIC-UDP stack和TCP-based版本的HTTP最重要的区别如下:
|
||||||
- QUIC集成了TLS 1.3协议中绝大部分特性,encryption从应用层移动到了传输层
|
- QUIC集成了TLS 1.3协议中绝大部分特性,encryption从应用层移动到了传输层
|
||||||
- HTTP/3在不同的streams间并不会对连接进行多路复用,多路复用的特性是由QUIC在传输层执行的
|
- HTTP/3在不同的streams间并不会对连接进行多路复用,多路复用的特性是由QUIC在传输层执行的
|
||||||
- 传输层的多路复用移解决了HTTP/2中TCP中头部阻塞的问题(HTTP/1.1中并不存在头部阻塞问题,因为其会开启多个TCP连接,并且会提供pipelining选项,后来该方案被发现拥有严重实现缺陷,被替换为了HTTP/2中应用层的多路复用)
|
- 传输层的多路复用移解决了HTTP/2中TCP中头部阻塞的问题(HTTP/1.1中并不存在头部阻塞问题,因为其会开启多个TCP连接,并且会提供pipelining选项,后来该方案被发现拥有严重实现缺陷,被替换为了HTTP/2中应用层的多路复用)
|
||||||
|
|
||||||
## Best Features of HTTP/3 and QUIC
|
## Best Features of HTTP/3 and QUIC
|
||||||
HTTP/3和QUIC的新特性能够令server connections速度更快、传输更安全、可靠性更高。
|
HTTP/3和QUIC的新特性能够令server connections速度更快、传输更安全、可靠性更高。
|
||||||
|
|
||||||
### QUIC handshake
|
### QUIC handshake
|
||||||
在HTTP2中,client和server在执行handshake的过程中,至少需要2次round-trips:
|
在HTTP2中,client和server在执行handshake的过程中,至少需要2次round-trips:
|
||||||
- tcp handshake需要一次round-trip
|
- tcp handshake需要一次round-trip
|
||||||
- tls handleshake至少需要一次round-trip
|
- tls handleshake至少需要一次round-trip
|
||||||
|
|
||||||
和QUIC则将上述两次handshakes整合成了一个,HTTP3仅需一次round-trip就可以在client和server之间建立一个secure connection。`QUIC可以带来更快的连接建立和更低的延迟。`
|
和QUIC则将上述两次handshakes整合成了一个,HTTP3仅需一次round-trip就可以在client和server之间建立一个secure connection。`QUIC可以带来更快的连接建立和更低的延迟。`
|
||||||
|
|
||||||
QUIC集成了`TLS1.3`中的绝大多数特性,`TLS1.3`是目前最新版本的`Transport Layer Security`协议,其代表:
|
QUIC集成了`TLS1.3`中的绝大多数特性,`TLS1.3`是目前最新版本的`Transport Layer Security`协议,其代表:
|
||||||
- HTTP/3中,消息的加密是强制的,并不像HTTP/1.1和HTTP/2中一样是可选的。在使用HTTP/3时,所有的消息都默认通过encrypted connection来进行发送。
|
- HTTP/3中,消息的加密是强制的,并不像HTTP/1.1和HTTP/2中一样是可选的。在使用HTTP/3时,所有的消息都默认通过encrypted connection来进行发送。
|
||||||
- TLS 1.3引入了一个`improved cryptographic handshake`,在client和server间仅需要一次round-trip;而TLS 1.2中则需要两次round-trips用于认证
|
- TLS 1.3引入了一个`improved cryptographic handshake`,在client和server间仅需要一次round-trip;而TLS 1.2中则需要两次round-trips用于认证
|
||||||
- 而在QUIC中,则将该`improved cryptographic handshake`和其本身用于连接创建的handshake进行了整合,并替代了TCP的handshake
|
- 而在QUIC中,则将该`improved cryptographic handshake`和其本身用于连接创建的handshake进行了整合,并替代了TCP的handshake
|
||||||
- 在HTTP/3中,消息都是在传输层加密的,故而加密的信息比HTTP/1.1和HTTP/2中都更多
|
- 在HTTP/3中,消息都是在传输层加密的,故而加密的信息比HTTP/1.1和HTTP/2中都更多
|
||||||
- 在HTTP/1.1和HTTP/2协议栈中,TLS都运行在应用层,故而HTTP data是加密的,但是,TCP header则是明文发送的,TCP header的明文可能会带来一些安全问题
|
- 在HTTP/1.1和HTTP/2协议栈中,TLS都运行在应用层,故而HTTP data是加密的,但是,TCP header则是明文发送的,TCP header的明文可能会带来一些安全问题
|
||||||
- 在HTTP/3 stack中,TLS运行在传输层,故而不仅http message被加密,大多数QUIC packet header也是被加密的
|
- 在HTTP/3 stack中,TLS运行在传输层,故而不仅http message被加密,大多数QUIC packet header也是被加密的
|
||||||
|
|
||||||
简单来说,HTTP/3使用的传输机制相比于TCP-based HTTP版本来说要更加安全。(传输层协议本身的header也被加密)
|
简单来说,HTTP/3使用的传输机制相比于TCP-based HTTP版本来说要更加安全。(传输层协议本身的header也被加密)
|
||||||
|
|
||||||
### 0-RTT on Prior Connections
|
### 0-RTT on Prior Connections
|
||||||
对于先前存在的connections,QUIC利用了TLS 1.3的`0-RTT`特性。
|
对于先前存在的connections,QUIC利用了TLS 1.3的`0-RTT`特性。
|
||||||
|
|
||||||
`0-RTT`代表zero round-trip time resumption,是TLS 1.3中引入的一个新特性。
|
`0-RTT`代表zero round-trip time resumption,是TLS 1.3中引入的一个新特性。
|
||||||
|
|
||||||
TLS session resumption通过复用先前建立的安全参数,减少建立secure connection所花费的时间。当client和server频繁建立连接并断开时,这将带来性能改善。
|
TLS session resumption通过复用先前建立的安全参数,减少建立secure connection所花费的时间。当client和server频繁建立连接并断开时,这将带来性能改善。
|
||||||
|
|
||||||
通过0-RTT resumption,client可以在连接的第一个round-trip中发送http请求,复用先前建立的cryptographic keys。
|
通过0-RTT resumption,client可以在连接的第一个round-trip中发送http请求,复用先前建立的cryptographic keys。
|
||||||
|
|
||||||
下面展示了H2和H3 stack在建立连接时的区别:
|
下面展示了H2和H3 stack在建立连接时的区别:
|
||||||
|
|
||||||
<img loading="lazy" alt="Connection setup in the HTTP/2 vs HTTP/3 stacks" src="https://www.debugbear.com/assets/images/http2-vs-http3-roundtrips-1b14a7c6b6f7badbd345f67895dbf142.jpg" width="2063" height="1406" style="border-radius:4px" data-abc="true" class="img_CujE">
|
<img loading="lazy" alt="Connection setup in the HTTP/2 vs HTTP/3 stacks" src="https://www.debugbear.com/assets/images/http2-vs-http3-roundtrips-1b14a7c6b6f7badbd345f67895dbf142.jpg" width="2063" height="1406" style="border-radius:4px" data-abc="true" class="img_CujE">
|
||||||
|
|
||||||
- 当使用HTTP2和TLS 1.2时,client发送第一个http request需要4个round-trip
|
- 当使用HTTP2和TLS 1.2时,client发送第一个http request需要4个round-trip
|
||||||
- 在使用HTTP2和TLS 1.3时,client发送第一个http equest需要2、3个round-trip(根据是否使用0-rtt有所不同)
|
- 在使用HTTP2和TLS 1.3时,client发送第一个http equest需要2、3个round-trip(根据是否使用0-rtt有所不同)
|
||||||
- 在使用HTTP3和QUIC时,其默认包含TLS 1.3,其可以在1、2个round-trip内发送第一个http请求(根据是否复用先前连接的加密信息)
|
- 在使用HTTP3和QUIC时,其默认包含TLS 1.3,其可以在1、2个round-trip内发送第一个http请求(根据是否复用先前连接的加密信息)
|
||||||
|
|
||||||
### Head-of-Line Blocking Removal
|
### Head-of-Line Blocking Removal
|
||||||
HTTP/3协议栈和HTTP/2协议栈的结构不同,其解决了HTTP/2中最大的性能问题:`head-of-line`阻塞。
|
HTTP/3协议栈和HTTP/2协议栈的结构不同,其解决了HTTP/2中最大的性能问题:`head-of-line`阻塞。
|
||||||
- 该问题主要发生在HTTP/2中packet丢失的场景下,直到丢失的包被重传前,整个的数据传输过程都会停止,所有packets都必须在网络上等待,这将会导致页面的加载时间延长
|
- 该问题主要发生在HTTP/2中packet丢失的场景下,直到丢失的包被重传前,整个的数据传输过程都会停止,所有packets都必须在网络上等待,这将会导致页面的加载时间延长
|
||||||
|
|
||||||
在HTTP/3中,行首阻塞通过原生的多路复用解决了。这是QUIC最重要的特性之一。
|
在HTTP/3中,行首阻塞通过原生的多路复用解决了。这是QUIC最重要的特性之一。
|
||||||
|
|
||||||
#### HOL blocking术语
|
#### HOL blocking术语
|
||||||
如下是HOL问题涉及到的概念:
|
如下是HOL问题涉及到的概念:
|
||||||
- byte stream:是通过网络发送的字节序列。bytes作为不同大小的packets被传输。byte stream本质上是单个资源(file)的物理表现形式,通过网络来发送
|
- byte stream:是通过网络发送的字节序列。bytes作为不同大小的packets被传输。byte stream本质上是单个资源(file)的物理表现形式,通过网络来发送
|
||||||
- 复用:通过复用,可以在一个connection上传输多个byte streams,这将代表浏览器可以在同一个连接上同时加载多个文件
|
- 复用:通过复用,可以在一个connection上传输多个byte streams,这将代表浏览器可以在同一个连接上同时加载多个文件
|
||||||
- 在HTTP/1.1中,并不支持复用,其会未每个byte stream新开一个tcp连接。HTTP/2中引入了应用层的复用,其只会建立一个TCP连接,并通过其传输所有byte streams。故而,仅有HTTP/2会存在HOL问题
|
- 在HTTP/1.1中,并不支持复用,其会未每个byte stream新开一个tcp连接。HTTP/2中引入了应用层的复用,其只会建立一个TCP连接,并通过其传输所有byte streams。故而,仅有HTTP/2会存在HOL问题
|
||||||
- HOL blocking:这是由tcp byte stream抽象造成的性能问题。TCP并不知晓其所传输的数据,并将其所传输的所有数据都看作一个byte stream。故而,如果在网络传输过程中,任意位置的packet发生的丢失,所有在复用连接中的其他packets都会停止传输,并等待丢失的packets被重传
|
- HOL blocking:这是由tcp byte stream抽象造成的性能问题。TCP并不知晓其所传输的数据,并将其所传输的所有数据都看作一个byte stream。故而,如果在网络传输过程中,任意位置的packet发生的丢失,所有在复用连接中的其他packets都会停止传输,并等待丢失的packets被重传
|
||||||
- 这代表,复用的连接中,所有byte streams都会被TCP协议看作是一个byte stream,故而stream A中的packet丢失也会造成stream B的传输被阻塞,直至丢失packet被重传
|
- 这代表,复用的连接中,所有byte streams都会被TCP协议看作是一个byte stream,故而stream A中的packet丢失也会造成stream B的传输被阻塞,直至丢失packet被重传
|
||||||
- 并且,TCP使用了in-order传输,如果发生packet丢失,那么将阻塞整个的传输过程。在高丢包率的环境下,这将极大程度上影响传输速度。即使在HTTP/2中已经引入了性能优化特性,在2%丢包率的场景下,也会比HTTP/1.1的传输速度更慢
|
- 并且,TCP使用了in-order传输,如果发生packet丢失,那么将阻塞整个的传输过程。在高丢包率的环境下,这将极大程度上影响传输速度。即使在HTTP/2中已经引入了性能优化特性,在2%丢包率的场景下,也会比HTTP/1.1的传输速度更慢
|
||||||
- native multiplexing:在HTTP/3协议栈中,复用被移动到了传输层,实现了原生复用。QUIC通过stream ID来表示每个byte stream,并不像TCP一样将所有byte streams都看作是一个。
|
- native multiplexing:在HTTP/3协议栈中,复用被移动到了传输层,实现了原生复用。QUIC通过stream ID来表示每个byte stream,并不像TCP一样将所有byte streams都看作是一个。
|
||||||
|
|
||||||
#### How does QUIC remove head-of-line blocking
|
#### How does QUIC remove head-of-line blocking
|
||||||
QUIC基于UDP实现,其使用了out-of-order delivery,故而每个byte stream都通过网络独立的进行传输。然而,为了可靠性,QUIC确保了在同一byte stream内packets的in-order delivery,故而相同请求中关联的数据到达的顺序是一致的。
|
QUIC基于UDP实现,其使用了out-of-order delivery,故而每个byte stream都通过网络独立的进行传输。然而,为了可靠性,QUIC确保了在同一byte stream内packets的in-order delivery,故而相同请求中关联的数据到达的顺序是一致的。
|
||||||
|
|
||||||
QUIC标识了所有byte stream,并且streams是独立进行传输的,如果发生packet丢失,其他byte streams并不会停止并等待重传。
|
QUIC标识了所有byte stream,并且streams是独立进行传输的,如果发生packet丢失,其他byte streams并不会停止并等待重传。
|
||||||
|
|
||||||
下图中展示了QUIC原生复用和HTTP2应用层复用的区别:
|
下图中展示了QUIC原生复用和HTTP2应用层复用的区别:
|
||||||
<img loading="lazy" alt="HTTP/2 vs QUIC multiplexing diagrams" src="https://www.debugbear.com/assets/images/http2-vs-quic-multiplexing-36d594c1c356cae410fe60cfc2945d91.jpg" width="900" height="532" style="border-radius:4px" data-abc="true" class="img_CujE">
|
<img loading="lazy" alt="HTTP/2 vs QUIC multiplexing diagrams" src="https://www.debugbear.com/assets/images/http2-vs-quic-multiplexing-36d594c1c356cae410fe60cfc2945d91.jpg" width="900" height="532" style="border-radius:4px" data-abc="true" class="img_CujE">
|
||||||
|
|
||||||
如上图所示,HTTP/2和HTTP/3在传输多个资源时,都只创建了一个连接。但是,QUIC中不同byte streams是独立传输的,拥有不同的传输路径,并且不同byte streams之间不会彼此阻塞。
|
如上图所示,HTTP/2和HTTP/3在传输多个资源时,都只创建了一个连接。但是,QUIC中不同byte streams是独立传输的,拥有不同的传输路径,并且不同byte streams之间不会彼此阻塞。
|
||||||
|
|
||||||
即使QUIC解决了HTTP/2中引入的HOL问题,乱序传输也会存在弊端:byte streams并不会按照其被发送的顺序到达。例如,在使用乱序传输时,最不重要的资源可能会最先到达。
|
即使QUIC解决了HTTP/2中引入的HOL问题,乱序传输也会存在弊端:byte streams并不会按照其被发送的顺序到达。例如,在使用乱序传输时,最不重要的资源可能会最先到达。
|
||||||
|
|
||||||
#### Flexible Bandwidth Management
|
#### Flexible Bandwidth Management
|
||||||
带宽管理用于在packets和streams之间按照最优的方式对网络带宽进行分配。这是至关重要的功能,发送方和接收方的机器以及二者之间的网络节点处理packets的速度都有所不同,并且速度也会动态变化。
|
带宽管理用于在packets和streams之间按照最优的方式对网络带宽进行分配。这是至关重要的功能,发送方和接收方的机器以及二者之间的网络节点处理packets的速度都有所不同,并且速度也会动态变化。
|
||||||
|
|
||||||
带宽管理有助于避免网络中的数据溢出和拥塞,这些问题可能会导致server响应速度变慢,同时也可能会带来安全问题。
|
带宽管理有助于避免网络中的数据溢出和拥塞,这些问题可能会导致server响应速度变慢,同时也可能会带来安全问题。
|
||||||
|
|
||||||
UDP中并没有内置带宽控制,QUIC则是在HTTP3协议栈中负责该功能,其对TCP带宽管理中的两大部分进行了重新实现:
|
UDP中并没有内置带宽控制,QUIC则是在HTTP3协议栈中负责该功能,其对TCP带宽管理中的两大部分进行了重新实现:
|
||||||
- 流控制: 其在接收方限制了数据发送的速率,用于避免发送方造成接收方过载
|
- 流控制: 其在接收方限制了数据发送的速率,用于避免发送方造成接收方过载
|
||||||
- 拥塞控制:其限制了发送方和接收方之间的路径中每一个节点的发送速率,用于避免网络拥塞
|
- 拥塞控制:其限制了发送方和接收方之间的路径中每一个节点的发送速率,用于避免网络拥塞
|
||||||
|
|
||||||
##### Pre-Stream Flow Control
|
##### Pre-Stream Flow Control
|
||||||
为了支持独立的stream,QUIC采用了per-stream based flow control。其在两个级别控制了stream data的带宽消耗:
|
为了支持独立的stream,QUIC采用了per-stream based flow control。其在两个级别控制了stream data的带宽消耗:
|
||||||
- 对于每个独立的流,都设置了一个可分配给其的最大数据数量
|
- 对于每个独立的流,都设置了一个可分配给其的最大数据数量
|
||||||
- 在整个连接范的围内,设置了active streams最大的累积数量
|
- 在整个连接范的围内,设置了active streams最大的累积数量
|
||||||
|
|
||||||
通过per-stream flow control,QUIC限制了同时可以发送的数据数量,用于避免接收方过载,并且在多个streams间大致公平的分配网络容量。
|
通过per-stream flow control,QUIC限制了同时可以发送的数据数量,用于避免接收方过载,并且在多个streams间大致公平的分配网络容量。
|
||||||
|
|
||||||
##### 拥塞控制算法
|
##### 拥塞控制算法
|
||||||
QUIC允许实现选择不同的拥塞控制算法,使用最广泛的算法如下:
|
QUIC允许实现选择不同的拥塞控制算法,使用最广泛的算法如下:
|
||||||
- NewReno:TCP使用的拥塞控制算法
|
- NewReno:TCP使用的拥塞控制算法
|
||||||
- CUBIC: 和NewReno类似,但是使用了cubic function而不是linear function
|
- CUBIC: 和NewReno类似,但是使用了cubic function而不是linear function
|
||||||
- BBR
|
- BBR
|
||||||
|
|
||||||
在网络状况较差的场景下,不同的拥塞控制算法性能可能存在较大差异。
|
在网络状况较差的场景下,不同的拥塞控制算法性能可能存在较大差异。
|
||||||
|
|
||||||
|
|||||||
@@ -1,109 +1,109 @@
|
|||||||
- [垃圾回收和引用](#垃圾回收和引用)
|
- [垃圾回收和引用](#垃圾回收和引用)
|
||||||
- [finalize](#finalize)
|
- [finalize](#finalize)
|
||||||
- [引用](#引用)
|
- [引用](#引用)
|
||||||
- [Reference](#reference)
|
- [Reference](#reference)
|
||||||
- [get](#get)
|
- [get](#get)
|
||||||
- [clear](#clear)
|
- [clear](#clear)
|
||||||
- [enqueue](#enqueue)
|
- [enqueue](#enqueue)
|
||||||
- [isEnqueue](#isenqueue)
|
- [isEnqueue](#isenqueue)
|
||||||
- [引用的可达性](#引用的可达性)
|
- [引用的可达性](#引用的可达性)
|
||||||
- [强可达(strongly reachable)](#强可达strongly-reachable)
|
- [强可达(strongly reachable)](#强可达strongly-reachable)
|
||||||
- [软可达(softly reachable)](#软可达softly-reachable)
|
- [软可达(softly reachable)](#软可达softly-reachable)
|
||||||
- [弱可达(weakly reachable)](#弱可达weakly-reachable)
|
- [弱可达(weakly reachable)](#弱可达weakly-reachable)
|
||||||
- [终结器可达(finalizer reachable)](#终结器可达finalizer-reachable)
|
- [终结器可达(finalizer reachable)](#终结器可达finalizer-reachable)
|
||||||
- [幽灵可达(phantom reachable)](#幽灵可达phantom-reachable)
|
- [幽灵可达(phantom reachable)](#幽灵可达phantom-reachable)
|
||||||
- [引用类型](#引用类型)
|
- [引用类型](#引用类型)
|
||||||
- [软引用(SoftReference)](#软引用softreference)
|
- [软引用(SoftReference)](#软引用softreference)
|
||||||
- [弱引用(WeakReference)](#弱引用weakreference)
|
- [弱引用(WeakReference)](#弱引用weakreference)
|
||||||
- [幽灵可达](#幽灵可达)
|
- [幽灵可达](#幽灵可达)
|
||||||
- [Weak Hash Map](#weak-hash-map)
|
- [Weak Hash Map](#weak-hash-map)
|
||||||
- [引用队列](#引用队列)
|
- [引用队列](#引用队列)
|
||||||
- [ReferenceQueue.poll](#referencequeuepoll)
|
- [ReferenceQueue.poll](#referencequeuepoll)
|
||||||
- [ReferenceQueue.remove](#referencequeueremove)
|
- [ReferenceQueue.remove](#referencequeueremove)
|
||||||
- [弱引用和软引用的使用](#弱引用和软引用的使用)
|
- [弱引用和软引用的使用](#弱引用和软引用的使用)
|
||||||
|
|
||||||
# 垃圾回收和引用
|
# 垃圾回收和引用
|
||||||
## finalize
|
## finalize
|
||||||
finalize方法将会在对象的空间被回收之前被调用。如果一个对象被垃圾回收器判为不可达而需要被回收时,垃圾回收器将调用该对象的finalize方法,通过finalize方法可以清除对象的一些非内存资源。
|
finalize方法将会在对象的空间被回收之前被调用。如果一个对象被垃圾回收器判为不可达而需要被回收时,垃圾回收器将调用该对象的finalize方法,通过finalize方法可以清除对象的一些非内存资源。
|
||||||
在每个对象中,finalize方法最多被调用一次。
|
在每个对象中,finalize方法最多被调用一次。
|
||||||
> finalize方法可以抛出任何异常,但是抛出的异常将被垃圾回收器忽略。
|
> finalize方法可以抛出任何异常,但是抛出的异常将被垃圾回收器忽略。
|
||||||
|
|
||||||
在finalize方法调用时,该对象引用的其他对象可能也是垃圾对象,并且已经被回收。
|
在finalize方法调用时,该对象引用的其他对象可能也是垃圾对象,并且已经被回收。
|
||||||
## 引用
|
## 引用
|
||||||
### Reference
|
### Reference
|
||||||
Reference是一个抽象类,是所有特定引用类的父类。
|
Reference是一个抽象类,是所有特定引用类的父类。
|
||||||
#### get
|
#### get
|
||||||
```java
|
```java
|
||||||
public Object get()
|
public Object get()
|
||||||
```
|
```
|
||||||
将会返回引用对象指向的被引用对象
|
将会返回引用对象指向的被引用对象
|
||||||
#### clear
|
#### clear
|
||||||
```java
|
```java
|
||||||
public void clear()
|
public void clear()
|
||||||
```
|
```
|
||||||
清空引用对象从而使其不指向任何对象
|
清空引用对象从而使其不指向任何对象
|
||||||
#### enqueue
|
#### enqueue
|
||||||
```java
|
```java
|
||||||
public boolean enqueue()
|
public boolean enqueue()
|
||||||
```
|
```
|
||||||
如果存在引用对象,将引用对象加入到注册的引用队列中,如果加入队列成功,返回true;如果没有成功加入到队列,或者该引用对象已经在队列中,那么返回false
|
如果存在引用对象,将引用对象加入到注册的引用队列中,如果加入队列成功,返回true;如果没有成功加入到队列,或者该引用对象已经在队列中,那么返回false
|
||||||
#### isEnqueue
|
#### isEnqueue
|
||||||
```java
|
```java
|
||||||
public boolean isEnqueue()
|
public boolean isEnqueue()
|
||||||
```
|
```
|
||||||
如果该引用对象已经被加入到引用队列中,那么返回true,否则返回false
|
如果该引用对象已经被加入到引用队列中,那么返回true,否则返回false
|
||||||
### 引用的可达性
|
### 引用的可达性
|
||||||
#### 强可达(strongly reachable)
|
#### 强可达(strongly reachable)
|
||||||
至少通过一条强引用链可达
|
至少通过一条强引用链可达
|
||||||
#### 软可达(softly reachable)
|
#### 软可达(softly reachable)
|
||||||
不是强可达,但是至少可以通过一条包含软引用的引用链可达
|
不是强可达,但是至少可以通过一条包含软引用的引用链可达
|
||||||
#### 弱可达(weakly reachable)
|
#### 弱可达(weakly reachable)
|
||||||
不是弱可达,但是至少通过一条包含弱引用的引用链可达
|
不是弱可达,但是至少通过一条包含弱引用的引用链可达
|
||||||
#### 终结器可达(finalizer reachable)
|
#### 终结器可达(finalizer reachable)
|
||||||
不是弱可达,但是该对象的finalize方法尚未执行
|
不是弱可达,但是该对象的finalize方法尚未执行
|
||||||
#### 幽灵可达(phantom reachable)
|
#### 幽灵可达(phantom reachable)
|
||||||
如果finalize方法已经执行,但是可通过至少一条包含幽灵引用的引用链可达
|
如果finalize方法已经执行,但是可通过至少一条包含幽灵引用的引用链可达
|
||||||
### 引用类型
|
### 引用类型
|
||||||
#### 软引用(SoftReference)
|
#### 软引用(SoftReference)
|
||||||
对于软可达的对象,垃圾回收程序会随意进行处置,如果可用内存很低,回收器会清空SoftReference对象中的引用,之后该被引用对象则能被回收
|
对于软可达的对象,垃圾回收程序会随意进行处置,如果可用内存很低,回收器会清空SoftReference对象中的引用,之后该被引用对象则能被回收
|
||||||
> 在抛出OOM之前,所有的SoftReference引用将会被清空
|
> 在抛出OOM之前,所有的SoftReference引用将会被清空
|
||||||
|
|
||||||
#### 弱引用(WeakReference)
|
#### 弱引用(WeakReference)
|
||||||
弱可达对象将会被垃圾回收器回收,如果垃圾回收器认为对象是弱可达的,所有指向其的WeakReference对象都会被清空
|
弱可达对象将会被垃圾回收器回收,如果垃圾回收器认为对象是弱可达的,所有指向其的WeakReference对象都会被清空
|
||||||
|
|
||||||
#### 幽灵可达
|
#### 幽灵可达
|
||||||
幽灵可达并不是真正的可达,虚引用并不会影响对象的生命周期,如果一个对象和虚引用关联,则该对象跟没有与该虚引用关联一样,在任何时候都有可能被垃圾回收。虚引用主要用于跟踪对象垃圾回收的活动。
|
幽灵可达并不是真正的可达,虚引用并不会影响对象的生命周期,如果一个对象和虚引用关联,则该对象跟没有与该虚引用关联一样,在任何时候都有可能被垃圾回收。虚引用主要用于跟踪对象垃圾回收的活动。
|
||||||
|
|
||||||
### Weak Hash Map
|
### Weak Hash Map
|
||||||
WeakHashMap会使用WeakReference来存储key。
|
WeakHashMap会使用WeakReference来存储key。
|
||||||
如果垃圾回收器发现一个对象弱可达时,会将弱引用放入到引用队列中。WeakHashMap会定期检查引用队列中新到达的弱引用,并且新到的弱引用代表该key不再被使用,WeakHashMap会移除关联的entry。
|
如果垃圾回收器发现一个对象弱可达时,会将弱引用放入到引用队列中。WeakHashMap会定期检查引用队列中新到达的弱引用,并且新到的弱引用代表该key不再被使用,WeakHashMap会移除关联的entry。
|
||||||
|
|
||||||
|
|
||||||
### 引用队列
|
### 引用队列
|
||||||
如果对象的可达性状态发生了改变,那么执行该对象的引用类型将会被放置到引用队列中。引用队列通常被垃圾回收器使用。
|
如果对象的可达性状态发生了改变,那么执行该对象的引用类型将会被放置到引用队列中。引用队列通常被垃圾回收器使用。
|
||||||
也可以在自己的代码中对引用队列进行使用,通过引用队列,可以监听对象的可达性改变。
|
也可以在自己的代码中对引用队列进行使用,通过引用队列,可以监听对象的可达性改变。
|
||||||
> 例如当对象不再被强引用,变为弱可达时,引用将会被添加到引用队列中,再通过代码监听引用队列的变化,即可监听到对象可达性的变化
|
> 例如当对象不再被强引用,变为弱可达时,引用将会被添加到引用队列中,再通过代码监听引用队列的变化,即可监听到对象可达性的变化
|
||||||
|
|
||||||
> ReferenceQueue是线程安全的。
|
> ReferenceQueue是线程安全的。
|
||||||
|
|
||||||
#### ReferenceQueue.poll
|
#### ReferenceQueue.poll
|
||||||
```java
|
```java
|
||||||
pulbic Reference poll()
|
pulbic Reference poll()
|
||||||
```
|
```
|
||||||
该方法会删除并且返回队列中的下一个引用对象,若队列为空,则返回值为null
|
该方法会删除并且返回队列中的下一个引用对象,若队列为空,则返回值为null
|
||||||
|
|
||||||
#### ReferenceQueue.remove
|
#### ReferenceQueue.remove
|
||||||
```java
|
```java
|
||||||
public Reference remove() throws InterruptedException
|
public Reference remove() throws InterruptedException
|
||||||
```
|
```
|
||||||
该方法同样会删除并返回队列中下一个引用对象,但是该方法在队列为空时会无限阻塞下去
|
该方法同样会删除并返回队列中下一个引用对象,但是该方法在队列为空时会无限阻塞下去
|
||||||
```java
|
```java
|
||||||
public Reference remove(long timeout) throws InterruptedException
|
public Reference remove(long timeout) throws InterruptedException
|
||||||
```
|
```
|
||||||
|
|
||||||
引用对象在构造时,会和特定的引用队列相关联,当被引用对象的可达性状态发生变化时,被添加到引用队列中。在被添加到队列之前,引用对象都已经被清空。
|
引用对象在构造时,会和特定的引用队列相关联,当被引用对象的可达性状态发生变化时,被添加到引用队列中。在被添加到队列之前,引用对象都已经被清空。
|
||||||
|
|
||||||
### 弱引用和软引用的使用
|
### 弱引用和软引用的使用
|
||||||
弱引用和软引用都提供两种类型的构造函数,
|
弱引用和软引用都提供两种类型的构造函数,
|
||||||
- 只接受被引用对象,并不将引用注册到引用队列
|
- 只接受被引用对象,并不将引用注册到引用队列
|
||||||
- 既接受被引用对象,还将引用注册到指定的引用队列,然后可以通过检查引用队列中的情况来监听被引用对象可达状态变更
|
- 既接受被引用对象,还将引用注册到指定的引用队列,然后可以通过检查引用队列中的情况来监听被引用对象可达状态变更
|
||||||
@@ -1,363 +1,363 @@
|
|||||||
- [文件](#文件)
|
- [文件](#文件)
|
||||||
- [参数](#参数)
|
- [参数](#参数)
|
||||||
- [参数查看](#参数查看)
|
- [参数查看](#参数查看)
|
||||||
- [参数类型](#参数类型)
|
- [参数类型](#参数类型)
|
||||||
- [动态参数修改](#动态参数修改)
|
- [动态参数修改](#动态参数修改)
|
||||||
- [静态参数修改](#静态参数修改)
|
- [静态参数修改](#静态参数修改)
|
||||||
- [日志文件](#日志文件)
|
- [日志文件](#日志文件)
|
||||||
- [错误日志](#错误日志)
|
- [错误日志](#错误日志)
|
||||||
- [慢查询日志](#慢查询日志)
|
- [慢查询日志](#慢查询日志)
|
||||||
- [log\_queries\_not\_using\_indexes](#log_queries_not_using_indexes)
|
- [log\_queries\_not\_using\_indexes](#log_queries_not_using_indexes)
|
||||||
- [查询日志](#查询日志)
|
- [查询日志](#查询日志)
|
||||||
- [二进制日志](#二进制日志)
|
- [二进制日志](#二进制日志)
|
||||||
- [max\_binlog\_size](#max_binlog_size)
|
- [max\_binlog\_size](#max_binlog_size)
|
||||||
- [binlog\_cache\_size](#binlog_cache_size)
|
- [binlog\_cache\_size](#binlog_cache_size)
|
||||||
- [binlog\_cache\_use](#binlog_cache_use)
|
- [binlog\_cache\_use](#binlog_cache_use)
|
||||||
- [binlog\_cache\_disk\_use](#binlog_cache_disk_use)
|
- [binlog\_cache\_disk\_use](#binlog_cache_disk_use)
|
||||||
- [sync\_binlog](#sync_binlog)
|
- [sync\_binlog](#sync_binlog)
|
||||||
- [innodb\_flush\_log\_at\_trx\_commit](#innodb_flush_log_at_trx_commit)
|
- [innodb\_flush\_log\_at\_trx\_commit](#innodb_flush_log_at_trx_commit)
|
||||||
- [binlog\_format](#binlog_format)
|
- [binlog\_format](#binlog_format)
|
||||||
- [使用statement可能会存在的问题](#使用statement可能会存在的问题)
|
- [使用statement可能会存在的问题](#使用statement可能会存在的问题)
|
||||||
- [mysqlbinlog](#mysqlbinlog)
|
- [mysqlbinlog](#mysqlbinlog)
|
||||||
- [pid文件](#pid文件)
|
- [pid文件](#pid文件)
|
||||||
- [表结构定义文件](#表结构定义文件)
|
- [表结构定义文件](#表结构定义文件)
|
||||||
- [表空间文件](#表空间文件)
|
- [表空间文件](#表空间文件)
|
||||||
- [innodb\_data\_file\_path](#innodb_data_file_path)
|
- [innodb\_data\_file\_path](#innodb_data_file_path)
|
||||||
- [innodb\_file\_per\_table](#innodb_file_per_table)
|
- [innodb\_file\_per\_table](#innodb_file_per_table)
|
||||||
- [redo log文件](#redo-log文件)
|
- [redo log文件](#redo-log文件)
|
||||||
- [循环写入](#循环写入)
|
- [循环写入](#循环写入)
|
||||||
- [redo log capacity](#redo-log-capacity)
|
- [redo log capacity](#redo-log-capacity)
|
||||||
- [redo log和binlog的区别](#redo-log和binlog的区别)
|
- [redo log和binlog的区别](#redo-log和binlog的区别)
|
||||||
- [记录内容](#记录内容)
|
- [记录内容](#记录内容)
|
||||||
- [写入时机](#写入时机)
|
- [写入时机](#写入时机)
|
||||||
- [redo log写入时机](#redo-log写入时机)
|
- [redo log写入时机](#redo-log写入时机)
|
||||||
|
|
||||||
|
|
||||||
# 文件
|
# 文件
|
||||||
## 参数
|
## 参数
|
||||||
### 参数查看
|
### 参数查看
|
||||||
mysql参数为键值对,可以通过`show variables`命令查看所有的数据库参数,并可以通过`like`来过滤参数名称。
|
mysql参数为键值对,可以通过`show variables`命令查看所有的数据库参数,并可以通过`like`来过滤参数名称。
|
||||||
|
|
||||||
除了`show variables`命令之外,还能够在`performance_schema`下的`global_variables`视图来查找数据库参数,示例如下:
|
除了`show variables`命令之外,还能够在`performance_schema`下的`global_variables`视图来查找数据库参数,示例如下:
|
||||||
```sql
|
```sql
|
||||||
-- 查看innodb_buffer_pool_size参数
|
-- 查看innodb_buffer_pool_size参数
|
||||||
show variables like 'innodb_buffer_pool_size'
|
show variables like 'innodb_buffer_pool_size'
|
||||||
```
|
```
|
||||||
上述`show variables`命令的执行结果为
|
上述`show variables`命令的执行结果为
|
||||||
| Variable\_name | Value |
|
| Variable\_name | Value |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| innodb\_buffer\_pool\_size | 4294967296 |
|
| innodb\_buffer\_pool\_size | 4294967296 |
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
select * from performance_schema.global_variables where variable_name like 'innodb_buffer_pool%';
|
select * from performance_schema.global_variables where variable_name like 'innodb_buffer_pool%';
|
||||||
```
|
```
|
||||||
上述sql的执行结果如下:
|
上述sql的执行结果如下:
|
||||||
| VARIABLE\_NAME | VARIABLE\_VALUE |
|
| VARIABLE\_NAME | VARIABLE\_VALUE |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| innodb\_buffer\_pool\_chunk\_size | 134217728 |
|
| innodb\_buffer\_pool\_chunk\_size | 134217728 |
|
||||||
| innodb\_buffer\_pool\_dump\_at\_shutdown | ON |
|
| innodb\_buffer\_pool\_dump\_at\_shutdown | ON |
|
||||||
| innodb\_buffer\_pool\_dump\_now | OFF |
|
| innodb\_buffer\_pool\_dump\_now | OFF |
|
||||||
| innodb\_buffer\_pool\_dump\_pct | 25 |
|
| innodb\_buffer\_pool\_dump\_pct | 25 |
|
||||||
| innodb\_buffer\_pool\_filename | ib\_buffer\_pool |
|
| innodb\_buffer\_pool\_filename | ib\_buffer\_pool |
|
||||||
| innodb\_buffer\_pool\_in\_core\_file | ON |
|
| innodb\_buffer\_pool\_in\_core\_file | ON |
|
||||||
| innodb\_buffer\_pool\_instances | 4 |
|
| innodb\_buffer\_pool\_instances | 4 |
|
||||||
| innodb\_buffer\_pool\_load\_abort | OFF |
|
| innodb\_buffer\_pool\_load\_abort | OFF |
|
||||||
| innodb\_buffer\_pool\_load\_at\_startup | ON |
|
| innodb\_buffer\_pool\_load\_at\_startup | ON |
|
||||||
| innodb\_buffer\_pool\_load\_now | OFF |
|
| innodb\_buffer\_pool\_load\_now | OFF |
|
||||||
| innodb\_buffer\_pool\_size | 4294967296 |
|
| innodb\_buffer\_pool\_size | 4294967296 |
|
||||||
|
|
||||||
### 参数类型
|
### 参数类型
|
||||||
mysql中的参数可以分为`动态`和`静态`两种类型,
|
mysql中的参数可以分为`动态`和`静态`两种类型,
|
||||||
- 动态:动态参数代表可以在mysql运行过程中进行修改
|
- 动态:动态参数代表可以在mysql运行过程中进行修改
|
||||||
- 静态:代表在整个实例的声明周期内都不得进行修改
|
- 静态:代表在整个实例的声明周期内都不得进行修改
|
||||||
|
|
||||||
#### 动态参数修改
|
#### 动态参数修改
|
||||||
对于动态参数,可以在运行时通过`SET`命令来进行修改,`SET`命令语法如下:
|
对于动态参数,可以在运行时通过`SET`命令来进行修改,`SET`命令语法如下:
|
||||||
```sql
|
```sql
|
||||||
set
|
set
|
||||||
| [global | session] system_var_name=expr
|
| [global | session] system_var_name=expr
|
||||||
| [@@global. | @@session. | @@] system_var_name = expr
|
| [@@global. | @@session. | @@] system_var_name = expr
|
||||||
```
|
```
|
||||||
在上述语法中,`global`和`session`关键字代表该动态参数的修改是针对`当前会话`还是针对`整个实例的生命周期`。
|
在上述语法中,`global`和`session`关键字代表该动态参数的修改是针对`当前会话`还是针对`整个实例的生命周期`。
|
||||||
|
|
||||||
- 有些动态参数只能在会话范围内进行修改,例如`autocommit`
|
- 有些动态参数只能在会话范围内进行修改,例如`autocommit`
|
||||||
- 有些参数修改后,实例整个生命周期内都会生效,例如`binglog_cache_size`
|
- 有些参数修改后,实例整个生命周期内都会生效,例如`binglog_cache_size`
|
||||||
- 有些参数既可以在会话范围内进行修改,又可以在实例声明周期范围内进行修改,例如`read_buffer_size`
|
- 有些参数既可以在会话范围内进行修改,又可以在实例声明周期范围内进行修改,例如`read_buffer_size`
|
||||||
|
|
||||||
使用示例如下:
|
使用示例如下:
|
||||||
|
|
||||||
查询read_buffer_size的global和session值
|
查询read_buffer_size的global和session值
|
||||||
```sql
|
```sql
|
||||||
-- 查询read_buffer_size的global和session值
|
-- 查询read_buffer_size的global和session值
|
||||||
select @@session.read_buffer_size,@@global.read_buffer_size;
|
select @@session.read_buffer_size,@@global.read_buffer_size;
|
||||||
```
|
```
|
||||||
返回结果为
|
返回结果为
|
||||||
|
|
||||||
| @@session.read\_buffer\_size | @@global.read\_buffer\_size |
|
| @@session.read\_buffer\_size | @@global.read\_buffer\_size |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| 131072 | 131072 |
|
| 131072 | 131072 |
|
||||||
|
|
||||||
设置@@session.read_buffer_size为524288
|
设置@@session.read_buffer_size为524288
|
||||||
```sql
|
```sql
|
||||||
set @@session.read_buffer_size = 1024 * 512;
|
set @@session.read_buffer_size = 1024 * 512;
|
||||||
```
|
```
|
||||||
设置后,再次查询read_buffer_size的global和session值,结果为
|
设置后,再次查询read_buffer_size的global和session值,结果为
|
||||||
| @@session.read\_buffer\_size | @@global.read\_buffer\_size |
|
| @@session.read\_buffer\_size | @@global.read\_buffer\_size |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| 524288 | 131072 |
|
| 524288 | 131072 |
|
||||||
|
|
||||||
在调用set命令修改session read_buffer_size参数后,session参数发生变化,但是global参数仍然为旧的值。
|
在调用set命令修改session read_buffer_size参数后,session参数发生变化,但是global参数仍然为旧的值。
|
||||||
|
|
||||||
> `set session xxx`命令并不会对global参数的值造成影响,新会话的参数值仍然为修改前的值。
|
> `set session xxx`命令并不会对global参数的值造成影响,新会话的参数值仍然为修改前的值。
|
||||||
|
|
||||||
之后,再对global read_buffer_size值进行修改,执行如下命令
|
之后,再对global read_buffer_size值进行修改,执行如下命令
|
||||||
```sql
|
```sql
|
||||||
set @@global.read_buffer_size = 496 * 1024;
|
set @@global.read_buffer_size = 496 * 1024;
|
||||||
```
|
```
|
||||||
执行该命令后,sesion和global参数值为
|
执行该命令后,sesion和global参数值为
|
||||||
| @@session.read\_buffer\_size | @@global.read\_buffer\_size |
|
| @@session.read\_buffer\_size | @@global.read\_buffer\_size |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| 524288 | 507904 |
|
| 524288 | 507904 |
|
||||||
|
|
||||||
> `set global xxx`命令只会修改global参数值,对session参数值不会造成影响,新的session其`session参数值, global参数值`和修改后的global参数值保持一致
|
> `set global xxx`命令只会修改global参数值,对session参数值不会造成影响,新的session其`session参数值, global参数值`和修改后的global参数值保持一致
|
||||||
|
|
||||||
> 即使针对参数的global值进行了修改,其影响范围是当前实例的整个生命周期,`但是,其并不会对参数文件中的参数值进行修改,故而下次启动mysql实例时,仍然会从参数文件中取值,新实例的值仍然是修改前的值`。
|
> 即使针对参数的global值进行了修改,其影响范围是当前实例的整个生命周期,`但是,其并不会对参数文件中的参数值进行修改,故而下次启动mysql实例时,仍然会从参数文件中取值,新实例的值仍然是修改前的值`。
|
||||||
>
|
>
|
||||||
> 如果想要修改下次启动实例的参数值,需要修改参数文件中该参数的值。(参数文件路径通常为`/etc/my.cnf`)
|
> 如果想要修改下次启动实例的参数值,需要修改参数文件中该参数的值。(参数文件路径通常为`/etc/my.cnf`)
|
||||||
|
|
||||||
#### 静态参数修改
|
#### 静态参数修改
|
||||||
在运行时,如果尝试对静态参数进行修改,那么会发生错误,示例如下:
|
在运行时,如果尝试对静态参数进行修改,那么会发生错误,示例如下:
|
||||||
```sql
|
```sql
|
||||||
> set global datadir='/db/mysql'
|
> set global datadir='/db/mysql'
|
||||||
[2025-01-30 15:05:17] [HY000][1238] Variable 'datadir' is a read only variable
|
[2025-01-30 15:05:17] [HY000][1238] Variable 'datadir' is a read only variable
|
||||||
```
|
```
|
||||||
## 日志文件
|
## 日志文件
|
||||||
mysql中常见日志文件如下
|
mysql中常见日志文件如下
|
||||||
- 错误日志(error log)
|
- 错误日志(error log)
|
||||||
- 二进制日志(binlog)
|
- 二进制日志(binlog)
|
||||||
- 慢查询日志(slow query log)
|
- 慢查询日志(slow query log)
|
||||||
- 查询日志(log)
|
- 查询日志(log)
|
||||||
|
|
||||||
### 错误日志
|
### 错误日志
|
||||||
错误日志针对mysql的启动、运行、关闭过程进行了记录,用户可以通过`show variables like 'log_error';`来获取错误日志的路径:
|
错误日志针对mysql的启动、运行、关闭过程进行了记录,用户可以通过`show variables like 'log_error';`来获取错误日志的路径:
|
||||||
```sql
|
```sql
|
||||||
show variables like 'log_error';
|
show variables like 'log_error';
|
||||||
```
|
```
|
||||||
其输出值如下:
|
其输出值如下:
|
||||||
| Variable\_name | Value |
|
| Variable\_name | Value |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| log\_error | /var/log/mysql/mysqld.log |
|
| log\_error | /var/log/mysql/mysqld.log |
|
||||||
|
|
||||||
当mysql数据库无法正常启动时,应当首先查看错误日志。
|
当mysql数据库无法正常启动时,应当首先查看错误日志。
|
||||||
|
|
||||||
### 慢查询日志
|
### 慢查询日志
|
||||||
慢查询日志存在一个阈值,通过`long_query_time`参数来进行控制,该参数默认值为`10`,代表慢查询的限制为10s。
|
慢查询日志存在一个阈值,通过`long_query_time`参数来进行控制,该参数默认值为`10`,代表慢查询的限制为10s。
|
||||||
|
|
||||||
通过`slow_query_log`参数,可以控制是否日志输出慢查询日志,默认为`OFF`,如果需要开启慢查询日志,需要将该值设置为`ON`。
|
通过`slow_query_log`参数,可以控制是否日志输出慢查询日志,默认为`OFF`,如果需要开启慢查询日志,需要将该值设置为`ON`。
|
||||||
|
|
||||||
关于慢查询日志的输出地点,可以通过`log_output`参数来进行控制。该参数默认为`FILE`,支持`FILE, TABLE, NONE`。`log_output`支持制定多个值,多个值之间可以通过`,`分隔,当值中包含`NONE`时,以`NONE`优先。
|
关于慢查询日志的输出地点,可以通过`log_output`参数来进行控制。该参数默认为`FILE`,支持`FILE, TABLE, NONE`。`log_output`支持制定多个值,多个值之间可以通过`,`分隔,当值中包含`NONE`时,以`NONE`优先。
|
||||||
|
|
||||||
#### log_queries_not_using_indexes
|
#### log_queries_not_using_indexes
|
||||||
当`log_queryies_not_using_indexes`开启时,如果运行的sql语句没有使用索引,那么这条sql同样会被输出到慢查询日志。该参数默认关闭。
|
当`log_queryies_not_using_indexes`开启时,如果运行的sql语句没有使用索引,那么这条sql同样会被输出到慢查询日志。该参数默认关闭。
|
||||||
|
|
||||||
`log_throttle_queries_not_using_idnexes`用于记录`每分钟允许记录到慢查询日志并且没有使用索引`的sql语句次数,该参数值默认为0,代表每分钟输出到慢查询日志中的数量没有限制。
|
`log_throttle_queries_not_using_idnexes`用于记录`每分钟允许记录到慢查询日志并且没有使用索引`的sql语句次数,该参数值默认为0,代表每分钟输出到慢查询日志中的数量没有限制。
|
||||||
|
|
||||||
该参数主要用于防止大量没有使用索引的sql添加到慢查询日志中,造成慢查询日志大小快速增加。
|
该参数主要用于防止大量没有使用索引的sql添加到慢查询日志中,造成慢查询日志大小快速增加。
|
||||||
|
|
||||||
当慢查询日志中的内容越来越多时,可以通过mysql提供的工具`mysqldumpslow`命令,示例如下:
|
当慢查询日志中的内容越来越多时,可以通过mysql提供的工具`mysqldumpslow`命令,示例如下:
|
||||||
```sql
|
```sql
|
||||||
mysqldumpslow -s at -n 10 ${slow_query_log_path}
|
mysqldumpslow -s at -n 10 ${slow_query_log_path}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 查询日志
|
### 查询日志
|
||||||
查询日志记录了对mysql数据库所有的请求信息,无论请求是否正确执行。
|
查询日志记录了对mysql数据库所有的请求信息,无论请求是否正确执行。
|
||||||
|
|
||||||
查询日志通过`general_log`参数来进行控制,默认该参数值为`OFF`.
|
查询日志通过`general_log`参数来进行控制,默认该参数值为`OFF`.
|
||||||
|
|
||||||
### 二进制日志
|
### 二进制日志
|
||||||
二进制日志(binary log)记录了针对mysql数据库执行的所有更改操作(不包含select以及show这类读操作)。
|
二进制日志(binary log)记录了针对mysql数据库执行的所有更改操作(不包含select以及show这类读操作)。
|
||||||
|
|
||||||
对于update操作等,即使没有对数据库进行修改(affected rows为0),也会被写入到binary log中。
|
对于update操作等,即使没有对数据库进行修改(affected rows为0),也会被写入到binary log中。
|
||||||
|
|
||||||
二进制日志的主要用途如下:
|
二进制日志的主要用途如下:
|
||||||
- 恢复(recovery):某些数据恢复需要二进制日志,例如在数据库全备份文件恢复后,用户可以通过二进制日志进行point-in-time的恢复
|
- 恢复(recovery):某些数据恢复需要二进制日志,例如在数据库全备份文件恢复后,用户可以通过二进制日志进行point-in-time的恢复
|
||||||
- 复制(replication):通过将一台主机(master)的binlog同步到另一台主机(slave),并且在另一台主机上执行该binlog,可以令slave与master进行实时同步
|
- 复制(replication):通过将一台主机(master)的binlog同步到另一台主机(slave),并且在另一台主机上执行该binlog,可以令slave与master进行实时同步
|
||||||
- 审计(audit):用户可以对binlog中的信息进行审计,判断是否存在对数据库进行的注入攻击
|
- 审计(audit):用户可以对binlog中的信息进行审计,判断是否存在对数据库进行的注入攻击
|
||||||
|
|
||||||
通过参数`log_bin`可以控制是否启用二进制日志。
|
通过参数`log_bin`可以控制是否启用二进制日志。
|
||||||
|
|
||||||
binlog通常存放在`datadir`参数所指定的目录路径下。在该路径下,还存在`binlog.index`文件,该文件为binlog的索引文件,文件内容包含所有binlog的文件名称。
|
binlog通常存放在`datadir`参数所指定的目录路径下。在该路径下,还存在`binlog.index`文件,该文件为binlog的索引文件,文件内容包含所有binlog的文件名称。
|
||||||
|
|
||||||
#### max_binlog_size
|
#### max_binlog_size
|
||||||
`max_binlog_size`参数控制单个binlog文件的最大大小,如果单个文件超过该值,会产生新的二进制文件,新binlog的后缀会+1,并且新文件的文件名会被记录到`.index`文件中。
|
`max_binlog_size`参数控制单个binlog文件的最大大小,如果单个文件超过该值,会产生新的二进制文件,新binlog的后缀会+1,并且新文件的文件名会被记录到`.index`文件中。
|
||||||
|
|
||||||
`max_binlog_size`的默认值大小为`1G`。
|
`max_binlog_size`的默认值大小为`1G`。
|
||||||
|
|
||||||
#### binlog_cache_size
|
#### binlog_cache_size
|
||||||
当使用innodb存储引擎时,所有未提交事务的binlog会被记录到缓存中,等到事务提交后,会将缓存中的binlog写入到文件中。缓存大小通过`binlog_cache_size`决定,该值默认为`32768`,即`32KB`。
|
当使用innodb存储引擎时,所有未提交事务的binlog会被记录到缓存中,等到事务提交后,会将缓存中的binlog写入到文件中。缓存大小通过`binlog_cache_size`决定,该值默认为`32768`,即`32KB`。
|
||||||
|
|
||||||
`binlog_cache_size`是基于会话的,`在每个线程开启一个事务时,mysql会自动分配一个大小为binlog_cache_size大小的缓存,因而该值不能设置过大`。
|
`binlog_cache_size`是基于会话的,`在每个线程开启一个事务时,mysql会自动分配一个大小为binlog_cache_size大小的缓存,因而该值不能设置过大`。
|
||||||
|
|
||||||
当一个事务的记录大于设定的`binlog_cache_size`时,mysql会将缓冲中的日志写入到一个临时文件中,故而,该值无法设置过小。
|
当一个事务的记录大于设定的`binlog_cache_size`时,mysql会将缓冲中的日志写入到一个临时文件中,故而,该值无法设置过小。
|
||||||
|
|
||||||
通过`show global status like 'binlog_cache%`命令可以查看`binlog_cache_use`和`binlog_cache_disk_use`的状态,可以通过上述两个状态判断binlog cache大小是否合适。
|
通过`show global status like 'binlog_cache%`命令可以查看`binlog_cache_use`和`binlog_cache_disk_use`的状态,可以通过上述两个状态判断binlog cache大小是否合适。
|
||||||
|
|
||||||
##### binlog_cache_use
|
##### binlog_cache_use
|
||||||
`binlog_cache_use`记录了使用缓冲写binlog的次数
|
`binlog_cache_use`记录了使用缓冲写binlog的次数
|
||||||
|
|
||||||
##### binlog_cache_disk_use
|
##### binlog_cache_disk_use
|
||||||
`binlog_cache_disk_use`记录了使用临时文件写二进制日志的次数
|
`binlog_cache_disk_use`记录了使用临时文件写二进制日志的次数
|
||||||
|
|
||||||
#### sync_binlog
|
#### sync_binlog
|
||||||
`sync_binlog`参数控制mysql server同步binlog到磁盘的频率,该值默认为`1`
|
`sync_binlog`参数控制mysql server同步binlog到磁盘的频率,该值默认为`1`
|
||||||
|
|
||||||
- 0: 如果参数值为0,代表mysql server禁用binary log同步到磁盘。mysql会依赖操作系统将binary log刷新到磁盘中,该设置性能最佳,但是遇到操作系统崩溃时,可能会出现mysql事务提交但是还没有同步到binary log的场景
|
- 0: 如果参数值为0,代表mysql server禁用binary log同步到磁盘。mysql会依赖操作系统将binary log刷新到磁盘中,该设置性能最佳,但是遇到操作系统崩溃时,可能会出现mysql事务提交但是还没有同步到binary log的场景
|
||||||
- 1: 如果参数值设置为1,代表在事务提交之前将binary log同步到磁盘中,该设置最安全,但是会增加disk write次数,对性能会带来负面影响。在操作系统崩溃的场景下,binlog中缺失的事务还只处于prepared状态,从而确保binlog中没有事务丢失
|
- 1: 如果参数值设置为1,代表在事务提交之前将binary log同步到磁盘中,该设置最安全,但是会增加disk write次数,对性能会带来负面影响。在操作系统崩溃的场景下,binlog中缺失的事务还只处于prepared状态,从而确保binlog中没有事务丢失
|
||||||
- N:当参数值被设置为非`0,1`的值时,每当n个binlog commit groups被收集到后,同步binlog到磁盘。在这种情况下,可能会发生事务提交但是还没有被刷新到binlog中,`当n值越大时,性能会越好,但是也会增加数据丢失的风险`
|
- N:当参数值被设置为非`0,1`的值时,每当n个binlog commit groups被收集到后,同步binlog到磁盘。在这种情况下,可能会发生事务提交但是还没有被刷新到binlog中,`当n值越大时,性能会越好,但是也会增加数据丢失的风险`
|
||||||
|
|
||||||
为了在使用innodb事务和replciation时获得最好的一致性和持久性,请使用如下设置:
|
为了在使用innodb事务和replciation时获得最好的一致性和持久性,请使用如下设置:
|
||||||
```cnf
|
```cnf
|
||||||
sync_binlog=1
|
sync_binlog=1
|
||||||
innodb_flush_log_at_trx_commit=1
|
innodb_flush_log_at_trx_commit=1
|
||||||
```
|
```
|
||||||
|
|
||||||
#### innodb_flush_log_at_trx_commit
|
#### innodb_flush_log_at_trx_commit
|
||||||
innodb_flush_log_at_trx_commit用于控制redo log的刷新。
|
innodb_flush_log_at_trx_commit用于控制redo log的刷新。
|
||||||
|
|
||||||
该参数用于平衡`commit操作ACID的合规性`以及`更高性能`。通过修改该参数值,可以实现更佳的性能,但是在崩溃时可能会丢失事务:
|
该参数用于平衡`commit操作ACID的合规性`以及`更高性能`。通过修改该参数值,可以实现更佳的性能,但是在崩溃时可能会丢失事务:
|
||||||
- 1: 1为该参数默认值,代表完全的ACID合规性,日志在每次事务提交后被写入并刷新到磁盘中
|
- 1: 1为该参数默认值,代表完全的ACID合规性,日志在每次事务提交后被写入并刷新到磁盘中
|
||||||
- 0: 日志每秒被写入和刷新到磁盘中,如果事务没有被刷新,那么日志将会在崩溃中被丢失
|
- 0: 日志每秒被写入和刷新到磁盘中,如果事务没有被刷新,那么日志将会在崩溃中被丢失
|
||||||
- 2: 每当事务提交后,日志将会被写入,并且每秒钟都会被刷新到磁盘中。如果事务没有被刷新,崩溃同样会造成日志的丢失
|
- 2: 每当事务提交后,日志将会被写入,并且每秒钟都会被刷新到磁盘中。如果事务没有被刷新,崩溃同样会造成日志的丢失
|
||||||
|
|
||||||
如果当前数据库为slave角色,那么其不会把`从master同步的binlog`写入到自己的binlog中,如果要实现`master=>slave=>slave`的同步架构,必须设置`log_slave_updates`参数。
|
如果当前数据库为slave角色,那么其不会把`从master同步的binlog`写入到自己的binlog中,如果要实现`master=>slave=>slave`的同步架构,必须设置`log_slave_updates`参数。
|
||||||
|
|
||||||
#### binlog_format
|
#### binlog_format
|
||||||
binlog_format用于控制二进制文件的格式,可能有如下取值:
|
binlog_format用于控制二进制文件的格式,可能有如下取值:
|
||||||
- statement: 二进制文件记录的是日志的逻辑sql语句
|
- statement: 二进制文件记录的是日志的逻辑sql语句
|
||||||
- row:记录表的行更改情况,默认值为`row`
|
- row:记录表的行更改情况,默认值为`row`
|
||||||
- mixed: 如果参数被配置为mixed,mysql默认会采用`statement`格式进行记录,但是在特定场景能够下会使用`row`格式:
|
- mixed: 如果参数被配置为mixed,mysql默认会采用`statement`格式进行记录,但是在特定场景能够下会使用`row`格式:
|
||||||
- 使用了uuid, user, current_user,found_rows, row_count等不确定函数
|
- 使用了uuid, user, current_user,found_rows, row_count等不确定函数
|
||||||
- 使用了insert delay语句
|
- 使用了insert delay语句
|
||||||
- 使用了用户自定义函数
|
- 使用了用户自定义函数
|
||||||
- 使用了临时表
|
- 使用了临时表
|
||||||
|
|
||||||
##### 使用statement可能会存在的问题
|
##### 使用statement可能会存在的问题
|
||||||
在使用statement格式时,可能会存在如下问题
|
在使用statement格式时,可能会存在如下问题
|
||||||
- master运行rand,uuid等不确定函数时,或使用触发器操作时,会导致主从服务器上的数据不一致
|
- master运行rand,uuid等不确定函数时,或使用触发器操作时,会导致主从服务器上的数据不一致
|
||||||
- innodb的默认事务隔离级别为`repetable_read`,如果使用`read_commited`级别时,statement格式可能会导致丢失更新的情况,从而令master和slave的数据不一致
|
- innodb的默认事务隔离级别为`repetable_read`,如果使用`read_commited`级别时,statement格式可能会导致丢失更新的情况,从而令master和slave的数据不一致
|
||||||
|
|
||||||
binlog为动态参数,可以在数据库运行时进行修改,并且可以针对session和global进行修改。
|
binlog为动态参数,可以在数据库运行时进行修改,并且可以针对session和global进行修改。
|
||||||
|
|
||||||
#### mysqlbinlog
|
#### mysqlbinlog
|
||||||
在查看二进制日志时,可以使用`mysqlbinlog`命令,示例如下
|
在查看二进制日志时,可以使用`mysqlbinlog`命令,示例如下
|
||||||
```bash
|
```bash
|
||||||
mysqlbinlog --start-position=203 ${binlog_path}
|
mysqlbinlog --start-position=203 ${binlog_path}
|
||||||
```
|
```
|
||||||
|
|
||||||
## pid文件
|
## pid文件
|
||||||
mysql实例启动时,会将进程id写入到一个文件中,该文件被称为pid文件。
|
mysql实例启动时,会将进程id写入到一个文件中,该文件被称为pid文件。
|
||||||
|
|
||||||
pid文件路径通过`pid_file`参数来进行控制,fedora中默认路径为`/run/mysqld/mysqld.pid`。
|
pid文件路径通过`pid_file`参数来进行控制,fedora中默认路径为`/run/mysqld/mysqld.pid`。
|
||||||
|
|
||||||
## 表结构定义文件
|
## 表结构定义文件
|
||||||
mysql中数据的存储是根据表进行的,每个表都有与之对应的文件。无论表采用何种存储引擎,都会存在一个以`frm`为后缀的文件,该文件中保存了该表的表结构定义。
|
mysql中数据的存储是根据表进行的,每个表都有与之对应的文件。无论表采用何种存储引擎,都会存在一个以`frm`为后缀的文件,该文件中保存了该表的表结构定义。
|
||||||
|
|
||||||
> mysql 8中,schema对应目录下不再包含frm文件。
|
> mysql 8中,schema对应目录下不再包含frm文件。
|
||||||
|
|
||||||
## 表空间文件
|
## 表空间文件
|
||||||
innodb采用将存储的数据按照表空间(tablespace)进行存放的设计。在默认配置下,将会有一个初始大小为10MB,名称为ibdata1的文件,该文件为默认的表空间文件。
|
innodb采用将存储的数据按照表空间(tablespace)进行存放的设计。在默认配置下,将会有一个初始大小为10MB,名称为ibdata1的文件,该文件为默认的表空间文件。
|
||||||
|
|
||||||
### innodb_data_file_path
|
### innodb_data_file_path
|
||||||
可以通过`innodb_data_file_path`参数对默认表空间文件进行设置,示例如下:
|
可以通过`innodb_data_file_path`参数对默认表空间文件进行设置,示例如下:
|
||||||
```sql
|
```sql
|
||||||
innodb_data_file_path=datafile_spec1[;datafile_spec2]...
|
innodb_data_file_path=datafile_spec1[;datafile_spec2]...
|
||||||
```
|
```
|
||||||
用户可以通过多个文件组成一个表空间,示例如下:
|
用户可以通过多个文件组成一个表空间,示例如下:
|
||||||
```sql
|
```sql
|
||||||
innodb_data_file_path=/db/ibdata1:2000M;/dr2/db/ibdata2:2000M;autoextend
|
innodb_data_file_path=/db/ibdata1:2000M;/dr2/db/ibdata2:2000M;autoextend
|
||||||
```
|
```
|
||||||
在上述配置中,表空间由`/db/ibdata1`和`/dr2/db/ibdata2`两个文件组成,如果两个文件位于不同的磁盘上,那么磁盘的负载将会被平均,数据库的整体性能将会被提高。
|
在上述配置中,表空间由`/db/ibdata1`和`/dr2/db/ibdata2`两个文件组成,如果两个文件位于不同的磁盘上,那么磁盘的负载将会被平均,数据库的整体性能将会被提高。
|
||||||
|
|
||||||
同时,在上述示例中,为两个文件都指定了后续属性,含义如下:
|
同时,在上述示例中,为两个文件都指定了后续属性,含义如下:
|
||||||
- ibdata1:文件大小为2000M
|
- ibdata1:文件大小为2000M
|
||||||
- ibdata2:文件大小为2000M,并且当文件大小被用完后,文件会自动增长
|
- ibdata2:文件大小为2000M,并且当文件大小被用完后,文件会自动增长
|
||||||
|
|
||||||
当`innodb_data_file_path`被设置后,所有基于innodb存储引擎的表,其数据都会记录到该共享表空间中。
|
当`innodb_data_file_path`被设置后,所有基于innodb存储引擎的表,其数据都会记录到该共享表空间中。
|
||||||
|
|
||||||
### innodb_file_per_table
|
### innodb_file_per_table
|
||||||
如果`innodb_file_per_table`被启用后(默认启用),则每个基于innodb存储引擎的表都可以有一个独立的表空间,独立表空间的命名规则为`表名+.ibd`。
|
如果`innodb_file_per_table`被启用后(默认启用),则每个基于innodb存储引擎的表都可以有一个独立的表空间,独立表空间的命名规则为`表名+.ibd`。
|
||||||
|
|
||||||
通过innodb_file_per_table,用户不需要将所有的数据都放置在默认的表空间中。
|
通过innodb_file_per_table,用户不需要将所有的数据都放置在默认的表空间中。
|
||||||
|
|
||||||
> `innodb_file_per_table`所产生的独立表空间文件,其仅存储该表的数据、索引和插入缓冲BITMAP信息,其余信息仍然存放在默认的表空间中。
|
> `innodb_file_per_table`所产生的独立表空间文件,其仅存储该表的数据、索引和插入缓冲BITMAP信息,其余信息仍然存放在默认的表空间中。
|
||||||
|
|
||||||
## redo log文件
|
## redo log文件
|
||||||
redo log是一个基于磁盘的数据结构,用于在crash recovery过程中纠正由`未完成事务写入的错误数据`。
|
redo log是一个基于磁盘的数据结构,用于在crash recovery过程中纠正由`未完成事务写入的错误数据`。
|
||||||
|
|
||||||
> 在一般操作中,redo log对那些`会造成表数据发生改变的请求`进行encode操作,请求通常由sql statement或地级别api发起。
|
> 在一般操作中,redo log对那些`会造成表数据发生改变的请求`进行encode操作,请求通常由sql statement或地级别api发起。
|
||||||
|
|
||||||
redo log通常代表磁盘上的redo log file。写入重做日志文件的数据通常基于受影响的记录进行编码。在数据被写入到redo log file中时,LSN值也会不断增加。
|
redo log通常代表磁盘上的redo log file。写入重做日志文件的数据通常基于受影响的记录进行编码。在数据被写入到redo log file中时,LSN值也会不断增加。
|
||||||
|
|
||||||
### 循环写入
|
### 循环写入
|
||||||
innodb会按顺序写入redo log文件,例如redo log file group中存在两个文件,innodb会先写文件1,文件1写满后会切换文件2,在文件2写满后,重新切换到文件1。
|
innodb会按顺序写入redo log文件,例如redo log file group中存在两个文件,innodb会先写文件1,文件1写满后会切换文件2,在文件2写满后,重新切换到文件1。
|
||||||
|
|
||||||
### redo log capacity
|
### redo log capacity
|
||||||
从mysql 8.0.30开始,`innodb_redo_log_capacity`参数用于控制redo log file占用磁盘空间的大小。该参数可以在实例启动时进行设置,也可以通过`set global`来进行设置。
|
从mysql 8.0.30开始,`innodb_redo_log_capacity`参数用于控制redo log file占用磁盘空间的大小。该参数可以在实例启动时进行设置,也可以通过`set global`来进行设置。
|
||||||
|
|
||||||
`innodb_redo_log_capacity`默认值为`104857600`,即`100M`。
|
`innodb_redo_log_capacity`默认值为`104857600`,即`100M`。
|
||||||
|
|
||||||
redo log文件默认位于`datadir`路径下的`#innodb_redo`目录下。innodb会尝试维护32个redo log file,每个redo log file文件大小都相同,为`1/32 * innodb_redo_log_capacity`。
|
redo log文件默认位于`datadir`路径下的`#innodb_redo`目录下。innodb会尝试维护32个redo log file,每个redo log file文件大小都相同,为`1/32 * innodb_redo_log_capacity`。
|
||||||
|
|
||||||
redo log file将会使用`#ib_redoN`的命名方式,`N`是redo log file number。
|
redo log file将会使用`#ib_redoN`的命名方式,`N`是redo log file number。
|
||||||
|
|
||||||
innodb redo log file分为如下两种:
|
innodb redo log file分为如下两种:
|
||||||
- ordinary:正在被使用的redo log file
|
- ordinary:正在被使用的redo log file
|
||||||
- spare:等待被使用的redo log file
|
- spare:等待被使用的redo log file
|
||||||
|
|
||||||
> 相比于ordinary redo log file,spare redo log file的名称中还包含了`_tmp`后缀
|
> 相比于ordinary redo log file,spare redo log file的名称中还包含了`_tmp`后缀
|
||||||
|
|
||||||
每个oridnary redo log file都关联了一个制定的LSN范围,可以通过查询`performance_schema.innodb_redo_log_files`表里获取LSN范围。
|
每个oridnary redo log file都关联了一个制定的LSN范围,可以通过查询`performance_schema.innodb_redo_log_files`表里获取LSN范围。
|
||||||
|
|
||||||
示例如下:
|
示例如下:
|
||||||
```sql
|
```sql
|
||||||
select file_name, start_lsn, end_lsn from performance_schema.innodb_redo_log_files;
|
select file_name, start_lsn, end_lsn from performance_schema.innodb_redo_log_files;
|
||||||
```
|
```
|
||||||
查询结果示例如下:
|
查询结果示例如下:
|
||||||
| file\_name | start\_lsn | end\_lsn |
|
| file\_name | start\_lsn | end\_lsn |
|
||||||
| :--- | :--- | :--- |
|
| :--- | :--- | :--- |
|
||||||
| ./#innodb\_redo/#ib\_redo6 | 19656704 | 22931456 |
|
| ./#innodb\_redo/#ib\_redo6 | 19656704 | 22931456 |
|
||||||
|
|
||||||
当执行checkpoint时,innodb会将checkpoint LSN存储在文件的header中,在recovery过程中,所有的redo log文件都将被检查,并且基于最大的LSN来执行恢复操作。
|
当执行checkpoint时,innodb会将checkpoint LSN存储在文件的header中,在recovery过程中,所有的redo log文件都将被检查,并且基于最大的LSN来执行恢复操作。
|
||||||
|
|
||||||
常用的redo log状态如下
|
常用的redo log状态如下
|
||||||
```bash
|
```bash
|
||||||
# resize operation status
|
# resize operation status
|
||||||
Innodb_redo_log_resize_status
|
Innodb_redo_log_resize_status
|
||||||
# 当前redo log capacity
|
# 当前redo log capacity
|
||||||
Innodb_redo_log_capacity_resized
|
Innodb_redo_log_capacity_resized
|
||||||
Innodb_redo_log_checkpoint_lsn
|
Innodb_redo_log_checkpoint_lsn
|
||||||
Innodb_redo_log_current_lsn
|
Innodb_redo_log_current_lsn
|
||||||
Innodb_redo_log_flushed_to_disk_lsn
|
Innodb_redo_log_flushed_to_disk_lsn
|
||||||
Innodb_redo_log_logical_size
|
Innodb_redo_log_logical_size
|
||||||
Innodb_redo_log_physical_size
|
Innodb_redo_log_physical_size
|
||||||
Innodb_redo_log_read_only
|
Innodb_redo_log_read_only
|
||||||
Innodb_redo_log_uuid
|
Innodb_redo_log_uuid
|
||||||
```
|
```
|
||||||
> 重做日志大小设置时,如果设置大小过大,那么在执行恢复操作时,可能需要花费很长时间;如果重做日志文件大小设置过小,可能会导致事务的日志需要多次切换重做日志文件。
|
> 重做日志大小设置时,如果设置大小过大,那么在执行恢复操作时,可能需要花费很长时间;如果重做日志文件大小设置过小,可能会导致事务的日志需要多次切换重做日志文件。
|
||||||
>
|
>
|
||||||
> 此外,重做日志太小会频繁发生async checkpoint,导致性能抖动。重做日志存在一个capacity,代表了最后的checkpoint不能够超过这个阈值,如果超过必须将缓冲区中的部分脏页刷新到磁盘中,此时可能会造成用户线程的阻塞。
|
> 此外,重做日志太小会频繁发生async checkpoint,导致性能抖动。重做日志存在一个capacity,代表了最后的checkpoint不能够超过这个阈值,如果超过必须将缓冲区中的部分脏页刷新到磁盘中,此时可能会造成用户线程的阻塞。
|
||||||
|
|
||||||
### redo log和binlog的区别
|
### redo log和binlog的区别
|
||||||
#### 记录内容
|
#### 记录内容
|
||||||
binlog记录的是一个事务的具体操作内容,该日志为逻辑日志。
|
binlog记录的是一个事务的具体操作内容,该日志为逻辑日志。
|
||||||
|
|
||||||
而innodb redo log记录的是关于某个页的修改,为物理日志。
|
而innodb redo log记录的是关于某个页的修改,为物理日志。
|
||||||
|
|
||||||
#### 写入时机
|
#### 写入时机
|
||||||
binlog仅当事务提交前才进行提交,即只会写磁盘一次。
|
binlog仅当事务提交前才进行提交,即只会写磁盘一次。
|
||||||
|
|
||||||
redo log则是在事务运行过程中,不断有重做日志被写入到redo log file中。
|
redo log则是在事务运行过程中,不断有重做日志被写入到redo log file中。
|
||||||
|
|
||||||
### redo log写入时机
|
### redo log写入时机
|
||||||
- master thread会每秒将redo log从buffer中刷新到redo log ile中,不露内事务是否已经提交
|
- master thread会每秒将redo log从buffer中刷新到redo log ile中,不露内事务是否已经提交
|
||||||
- innodb_flush_log_at_trx_commit控制redo log的刷新时机,默认情况下,在事务提交前会将数据从redo log buffer刷新到redo log file中
|
- innodb_flush_log_at_trx_commit控制redo log的刷新时机,默认情况下,在事务提交前会将数据从redo log buffer刷新到redo log file中
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,80 +1,80 @@
|
|||||||
- [CAP Theorem in DBMS](#cap-theorem-in-dbms)
|
- [CAP Theorem in DBMS](#cap-theorem-in-dbms)
|
||||||
- [What is the CAP Theorem](#what-is-the-cap-theorem)
|
- [What is the CAP Theorem](#what-is-the-cap-theorem)
|
||||||
- [Consistency](#consistency)
|
- [Consistency](#consistency)
|
||||||
- [Availability](#availability)
|
- [Availability](#availability)
|
||||||
- [Partition Tolerance](#partition-tolerance)
|
- [Partition Tolerance](#partition-tolerance)
|
||||||
- [The Trade-Offs in the CAP Theorem](#the-trade-offs-in-the-cap-theorem)
|
- [The Trade-Offs in the CAP Theorem](#the-trade-offs-in-the-cap-theorem)
|
||||||
- [CA(Consistency and Availability)](#caconsistency-and-availability)
|
- [CA(Consistency and Availability)](#caconsistency-and-availability)
|
||||||
- [AP(Availability and Partition Tolerance)](#apavailability-and-partition-tolerance)
|
- [AP(Availability and Partition Tolerance)](#apavailability-and-partition-tolerance)
|
||||||
- [CP(Consistency and Partition Tolerance)](#cpconsistency-and-partition-tolerance)
|
- [CP(Consistency and Partition Tolerance)](#cpconsistency-and-partition-tolerance)
|
||||||
|
|
||||||
# CAP Theorem in DBMS
|
# CAP Theorem in DBMS
|
||||||
在网络共享数据系统设计中固有的权衡令构建一个可靠且高效的系统十分困难。CAP理论是理解分布式系统中这些权衡的核心基础。CAP理论强调了系统设计者在处理distributed data replication时的局限性。CAP理论指出,在分布式系统中,只能同时满足`一致性、可用性、分区容错`这三个特性中的两种。
|
在网络共享数据系统设计中固有的权衡令构建一个可靠且高效的系统十分困难。CAP理论是理解分布式系统中这些权衡的核心基础。CAP理论强调了系统设计者在处理distributed data replication时的局限性。CAP理论指出,在分布式系统中,只能同时满足`一致性、可用性、分区容错`这三个特性中的两种。
|
||||||
|
|
||||||
> CAP理论中,对分布式系统提出了如下三个特性:
|
> CAP理论中,对分布式系统提出了如下三个特性:
|
||||||
> - consistency(一致性)
|
> - consistency(一致性)
|
||||||
> - availability(可用性)
|
> - availability(可用性)
|
||||||
> - partition tolerance(分区容错)
|
> - partition tolerance(分区容错)
|
||||||
|
|
||||||
由于该底层限制,开发者必须根据其应用的需要谨慎的平衡这些属性。设计者必须决定优先考虑哪些特性,从而获取最佳的性能和系统可靠性。
|
由于该底层限制,开发者必须根据其应用的需要谨慎的平衡这些属性。设计者必须决定优先考虑哪些特性,从而获取最佳的性能和系统可靠性。
|
||||||
|
|
||||||
## What is the CAP Theorem
|
## What is the CAP Theorem
|
||||||
CAP理论是分布式系统的基础概念,其指出分布式系统中所有的三个特性无法被同时满足。
|
CAP理论是分布式系统的基础概念,其指出分布式系统中所有的三个特性无法被同时满足。
|
||||||
|
|
||||||
### Consistency
|
### Consistency
|
||||||
`Consistency`代表network中所有的节点都包含相同的replicated data拷贝,而这些数据对不同事务可见。其保证分布式居群中所有节点返回相同、最新的数据。其代表所有client对数据的视角都相同。存在许多不同类型的一致性模型,而CAP中的一致性代指的是顺序一致性,是一种非常强的一致性形式。
|
`Consistency`代表network中所有的节点都包含相同的replicated data拷贝,而这些数据对不同事务可见。其保证分布式居群中所有节点返回相同、最新的数据。其代表所有client对数据的视角都相同。存在许多不同类型的一致性模型,而CAP中的一致性代指的是顺序一致性,是一种非常强的一致性形式。
|
||||||
|
|
||||||
`ACID`和`CAP`中都包含一致性,但是这两种一致性所有不同:
|
`ACID`和`CAP`中都包含一致性,但是这两种一致性所有不同:
|
||||||
- 在`ACID`中,其代表事务不能破坏数据库的完整性约束
|
- 在`ACID`中,其代表事务不能破坏数据库的完整性约束
|
||||||
- 在`CAP`中,其代表分布式系统中相同数据项在不同副本中的一致性
|
- 在`CAP`中,其代表分布式系统中相同数据项在不同副本中的一致性
|
||||||
|
|
||||||
### Availability
|
### Availability
|
||||||
Availability代表每个对数据项的read/write request要么能被成功处理,要么能收到一个操作无法被完成的响应。每个non-failing节点都会为所有读写请求在合理的时间范围内生成响应。
|
Availability代表每个对数据项的read/write request要么能被成功处理,要么能收到一个操作无法被完成的响应。每个non-failing节点都会为所有读写请求在合理的时间范围内生成响应。
|
||||||
|
|
||||||
其中,“每个节点”代表,即使发生network partition,节点只要不处于failing状态,无论位于network partition的哪一侧,都应该能在合理的时间范围内返回响应。
|
其中,“每个节点”代表,即使发生network partition,节点只要不处于failing状态,无论位于network partition的哪一侧,都应该能在合理的时间范围内返回响应。
|
||||||
|
|
||||||
### Partition Tolerance
|
### Partition Tolerance
|
||||||
partition tolerance代表在连接节点的网络发生错误、造成两个或多个分区时,系统仍然能够继续进行操作。通常,在出现network partition时,每个partition中的节点只能彼此互相沟通,跨分区的节点通信被阻断。
|
partition tolerance代表在连接节点的网络发生错误、造成两个或多个分区时,系统仍然能够继续进行操作。通常,在出现network partition时,每个partition中的节点只能彼此互相沟通,跨分区的节点通信被阻断。
|
||||||
|
|
||||||
这意味着,即使发生network partition,系统仍然能持续运行并保证其一致性。network partition是不可避免地,在网络分区恢复正常后,拥有partition tolerance的分布式系统能够优雅的从分区状态中恢复。
|
这意味着,即使发生network partition,系统仍然能持续运行并保证其一致性。network partition是不可避免地,在网络分区恢复正常后,拥有partition tolerance的分布式系统能够优雅的从分区状态中恢复。
|
||||||
|
|
||||||
CAP理论指出分布式数据库最多只能兼顾如下三个特性中的两种:consistency, availability, partition tolerance。
|
CAP理论指出分布式数据库最多只能兼顾如下三个特性中的两种:consistency, availability, partition tolerance。
|
||||||
|
|
||||||
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20240808172250/venndiagram.png" alt="CAP - venndiagram" width="390" height="321" srcset="https://media.geeksforgeeks.org/wp-content/uploads/20240808172250/venndiagram.png 390w,https://media.geeksforgeeks.org/wp-content/uploads/20240808172250/venndiagram-100.png 100w,https://media.geeksforgeeks.org/wp-content/uploads/20240808172250/venndiagram-200.png 200w,https://media.geeksforgeeks.org/wp-content/uploads/20240808172250/venndiagram-300.png 300w" loading="lazy">
|
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20240808172250/venndiagram.png" alt="CAP - venndiagram" width="390" height="321" srcset="https://media.geeksforgeeks.org/wp-content/uploads/20240808172250/venndiagram.png 390w,https://media.geeksforgeeks.org/wp-content/uploads/20240808172250/venndiagram-100.png 100w,https://media.geeksforgeeks.org/wp-content/uploads/20240808172250/venndiagram-200.png 200w,https://media.geeksforgeeks.org/wp-content/uploads/20240808172250/venndiagram-300.png 300w" loading="lazy">
|
||||||
|
|
||||||
## The Trade-Offs in the CAP Theorem
|
## The Trade-Offs in the CAP Theorem
|
||||||
CAP理论表明分布式系统中只能同时满足三种特性中的两种。
|
CAP理论表明分布式系统中只能同时满足三种特性中的两种。
|
||||||
### CA(Consistency and Availability)
|
### CA(Consistency and Availability)
|
||||||
> 对于CA类型的系统,其总是可以接收来源于用户的查询和修改数据请求,并且分布式网络中所有database nodes都会返回相同的响应
|
> 对于CA类型的系统,其总是可以接收来源于用户的查询和修改数据请求,并且分布式网络中所有database nodes都会返回相同的响应
|
||||||
|
|
||||||
然而,该种类似的分布式系统在现实世界中不可能存在,因为在network failure发生时,仅有如下两种选项:
|
然而,该种类似的分布式系统在现实世界中不可能存在,因为在network failure发生时,仅有如下两种选项:
|
||||||
- 发送network failure发生前复制的old data
|
- 发送network failure发生前复制的old data
|
||||||
- 不允许用户访问old data
|
- 不允许用户访问old data
|
||||||
|
|
||||||
如果我们选择第一个选项,那么系统将满足Availibility;如果选择第二个选项,系统则是Consistent。
|
如果我们选择第一个选项,那么系统将满足Availibility;如果选择第二个选项,系统则是Consistent。
|
||||||
|
|
||||||
`在分布式系统中,consistency和availability的组合是不可能的`。为了实现`CA`,系统必须是单体架构,当用户更新系统状态时,所有其他用户都能访问到该更新,这将代表系统满足一致性;而在单体架构中,所有用户都连接到一个节点上,这代表其是可用的。`CA`系统通常不被青睐,因为实现分布式计算必须牺牲consistency或availability中的一种,并将剩余的和partition tolerance组合,即`CP/AP`系统。
|
`在分布式系统中,consistency和availability的组合是不可能的`。为了实现`CA`,系统必须是单体架构,当用户更新系统状态时,所有其他用户都能访问到该更新,这将代表系统满足一致性;而在单体架构中,所有用户都连接到一个节点上,这代表其是可用的。`CA`系统通常不被青睐,因为实现分布式计算必须牺牲consistency或availability中的一种,并将剩余的和partition tolerance组合,即`CP/AP`系统。
|
||||||
|
|
||||||
> CAP中的A(Availability)只是要求非failing状态下的节点能够在合理的时间范围内返回响应,故而单体架构可以满足`Availability`。
|
> CAP中的A(Availability)只是要求非failing状态下的节点能够在合理的时间范围内返回响应,故而单体架构可以满足`Availability`。
|
||||||
>
|
>
|
||||||
> 即使单体架构可能因单点故障导致系统不可用,不满足`Reliable`(可靠性),并不影响其满足`Availability`(可用性)。
|
> 即使单体架构可能因单点故障导致系统不可用,不满足`Reliable`(可靠性),并不影响其满足`Availability`(可用性)。
|
||||||
|
|
||||||
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20240813184051/cap.png" alt="CA (Consistency and Availability)" width="631" height="579" srcset="https://media.geeksforgeeks.org/wp-content/uploads/20240813184051/cap.png 631w,https://media.geeksforgeeks.org/wp-content/uploads/20240813184051/cap-100.png 100w,https://media.geeksforgeeks.org/wp-content/uploads/20240813184051/cap-200.png 200w,https://media.geeksforgeeks.org/wp-content/uploads/20240813184051/cap-300.png 300w" loading="lazy">
|
<img src="https://media.geeksforgeeks.org/wp-content/uploads/20240813184051/cap.png" alt="CA (Consistency and Availability)" width="631" height="579" srcset="https://media.geeksforgeeks.org/wp-content/uploads/20240813184051/cap.png 631w,https://media.geeksforgeeks.org/wp-content/uploads/20240813184051/cap-100.png 100w,https://media.geeksforgeeks.org/wp-content/uploads/20240813184051/cap-200.png 200w,https://media.geeksforgeeks.org/wp-content/uploads/20240813184051/cap-300.png 300w" loading="lazy">
|
||||||
|
|
||||||
### AP(Availability and Partition Tolerance)
|
### AP(Availability and Partition Tolerance)
|
||||||
> 这种类型的系统本质上是分布式的,确保即使在network partition场景下,用户发送的针对database nodes中数据的查看和修改请求不会被丢失
|
> 这种类型的系统本质上是分布式的,确保即使在network partition场景下,用户发送的针对database nodes中数据的查看和修改请求不会被丢失
|
||||||
|
|
||||||
该系统优先考虑了Availability而非Consistency,并且可能会返回过期的数据。一些技术failure可能会导致partition,故而过期数据则是代表partition产生前被同步的数据。
|
该系统优先考虑了Availability而非Consistency,并且可能会返回过期的数据。一些技术failure可能会导致partition,故而过期数据则是代表partition产生前被同步的数据。
|
||||||
|
|
||||||
AP系统通常在构建社交媒体网站如Facebook和在线内容网站如YouTube时使用,其并不要求一致性。对于使用AP系统的场景,相比于不一致,不可用会造成更大的问题。
|
AP系统通常在构建社交媒体网站如Facebook和在线内容网站如YouTube时使用,其并不要求一致性。对于使用AP系统的场景,相比于不一致,不可用会造成更大的问题。
|
||||||
|
|
||||||
AP系统是分布式的,可以分布于多个节点,即使在network partition发生的前提下也能够可靠运行。
|
AP系统是分布式的,可以分布于多个节点,即使在network partition发生的前提下也能够可靠运行。
|
||||||
|
|
||||||
### CP(Consistency and Partition Tolerance)
|
### CP(Consistency and Partition Tolerance)
|
||||||
> 该类系统本质上是分布式的,确保由用户发起的针对database nodes中数据进行查看或修改的请求,在存在network partition的场景下,会直接被丢弃,而不是返回不一致的数据
|
> 该类系统本质上是分布式的,确保由用户发起的针对database nodes中数据进行查看或修改的请求,在存在network partition的场景下,会直接被丢弃,而不是返回不一致的数据
|
||||||
|
|
||||||
`CP`系统优先考虑了Consistency而非Availability,如果发生network partition,其不允许用户从replica读取`在network partition发生前同步的数据`。对于部分应用程序来说,相比于可用性,其更强调数据的一致性,例如股票交易系统、订票系统、银行系统等)
|
`CP`系统优先考虑了Consistency而非Availability,如果发生network partition,其不允许用户从replica读取`在network partition发生前同步的数据`。对于部分应用程序来说,相比于可用性,其更强调数据的一致性,例如股票交易系统、订票系统、银行系统等)
|
||||||
|
|
||||||
例如,在订票系统中,还剩余一个可订购座位。在该CP系统中,将会创建数据库的副本,并且将副本发送给系统中其他的节点。此时,如果发生网络问题,那么连接到partitioned node的用户将会从replica获取数据。此时,其他连接到unpartitioned部分的用户则可以对剩余的作为进行预定。这样,在连接到partitioned node的用户视角中,仍然存在一个seat,其将导致数据不一致。
|
例如,在订票系统中,还剩余一个可订购座位。在该CP系统中,将会创建数据库的副本,并且将副本发送给系统中其他的节点。此时,如果发生网络问题,那么连接到partitioned node的用户将会从replica获取数据。此时,其他连接到unpartitioned部分的用户则可以对剩余的作为进行预定。这样,在连接到partitioned node的用户视角中,仍然存在一个seat,其将导致数据不一致。
|
||||||
|
|
||||||
在上述场景下,CP系统通常会令其系统对`连接到partitioned node的用户`不可用。
|
在上述场景下,CP系统通常会令其系统对`连接到partitioned node的用户`不可用。
|
||||||
@@ -1,355 +1,355 @@
|
|||||||
- [Replication](#replication)
|
- [Replication](#replication)
|
||||||
- [Configuration Replication](#configuration-replication)
|
- [Configuration Replication](#configuration-replication)
|
||||||
- [binary log file position based replication configuration overview](#binary-log-file-position-based-replication-configuration-overview)
|
- [binary log file position based replication configuration overview](#binary-log-file-position-based-replication-configuration-overview)
|
||||||
- [Replication with Global Transaction Identifiers](#replication-with-global-transaction-identifiers)
|
- [Replication with Global Transaction Identifiers](#replication-with-global-transaction-identifiers)
|
||||||
- [GTID Format and Storage](#gtid-format-and-storage)
|
- [GTID Format and Storage](#gtid-format-and-storage)
|
||||||
- [GTID Sets](#gtid-sets)
|
- [GTID Sets](#gtid-sets)
|
||||||
- [msyql.gtid\_executed](#msyqlgtid_executed)
|
- [msyql.gtid\_executed](#msyqlgtid_executed)
|
||||||
- [mysql.gtid\_executed table compression](#mysqlgtid_executed-table-compression)
|
- [mysql.gtid\_executed table compression](#mysqlgtid_executed-table-compression)
|
||||||
- [GTID生命周期](#gtid生命周期)
|
- [GTID生命周期](#gtid生命周期)
|
||||||
- [What changes are assign a GTID](#what-changes-are-assign-a-gtid)
|
- [What changes are assign a GTID](#what-changes-are-assign-a-gtid)
|
||||||
- [Replication Implementation](#replication-implementation)
|
- [Replication Implementation](#replication-implementation)
|
||||||
- [Replication Formats](#replication-formats)
|
- [Replication Formats](#replication-formats)
|
||||||
- [使用statement-based和row-based replication的优缺点对比](#使用statement-based和row-based-replication的优缺点对比)
|
- [使用statement-based和row-based replication的优缺点对比](#使用statement-based和row-based-replication的优缺点对比)
|
||||||
- [Advantages of statement-based replication](#advantages-of-statement-based-replication)
|
- [Advantages of statement-based replication](#advantages-of-statement-based-replication)
|
||||||
- [Disadvantages of statement-based replication](#disadvantages-of-statement-based-replication)
|
- [Disadvantages of statement-based replication](#disadvantages-of-statement-based-replication)
|
||||||
- [Advantages of row-based replication](#advantages-of-row-based-replication)
|
- [Advantages of row-based replication](#advantages-of-row-based-replication)
|
||||||
- [disadvantages of row-based replication](#disadvantages-of-row-based-replication)
|
- [disadvantages of row-based replication](#disadvantages-of-row-based-replication)
|
||||||
- [Replay Log and Replication Metadata Repositories](#replay-log-and-replication-metadata-repositories)
|
- [Replay Log and Replication Metadata Repositories](#replay-log-and-replication-metadata-repositories)
|
||||||
- [The Relay Log](#the-relay-log)
|
- [The Relay Log](#the-relay-log)
|
||||||
|
|
||||||
# Replication
|
# Replication
|
||||||
Replication允许数据从一个database server被复制到一个或多个mysql database servers(replicas)。replication默认是异步的;replicas并无需永久连接即可接收来自source的更新。基于configuration,可以针对所有的databases、选定的databases、甚至database中指定的tables进行replicate。
|
Replication允许数据从一个database server被复制到一个或多个mysql database servers(replicas)。replication默认是异步的;replicas并无需永久连接即可接收来自source的更新。基于configuration,可以针对所有的databases、选定的databases、甚至database中指定的tables进行replicate。
|
||||||
|
|
||||||
mysql中replication包含如下优点:
|
mysql中replication包含如下优点:
|
||||||
- 可拓展方案:可以将负载分散到多个replicas,从而提升性能。在该环境中,所有的writes和updates都发生在source server。但是,reads则是可以发生在一个或多个replicas上。通过该模型,能够提升writes的性能(因为source专门用于更新),并可以通过增加replicas的数量来提高read speed
|
- 可拓展方案:可以将负载分散到多个replicas,从而提升性能。在该环境中,所有的writes和updates都发生在source server。但是,reads则是可以发生在一个或多个replicas上。通过该模型,能够提升writes的性能(因为source专门用于更新),并可以通过增加replicas的数量来提高read speed
|
||||||
- data security: 因为replica可以暂停replication过程,故而可以在replica中运行备份服务,而不会破坏对应的source data
|
- data security: 因为replica可以暂停replication过程,故而可以在replica中运行备份服务,而不会破坏对应的source data
|
||||||
- analytics:实时数据可以在source中生成,而对信息的分析则可以发生在replica,分析过程不会影响source的性能
|
- analytics:实时数据可以在source中生成,而对信息的分析则可以发生在replica,分析过程不会影响source的性能
|
||||||
- long-distance data distribution:可以replication来对remote site创建一个local copy,而无需对source的永久访问
|
- long-distance data distribution:可以replication来对remote site创建一个local copy,而无需对source的永久访问
|
||||||
|
|
||||||
在mysql 8.4中,支持不同的replication方式。
|
在mysql 8.4中,支持不同的replication方式。
|
||||||
- 传统方式基于从source的binary log中复制事件,并且需要log files和`在source和replica之间进行同步的position`。
|
- 传统方式基于从source的binary log中复制事件,并且需要log files和`在source和replica之间进行同步的position`。
|
||||||
- 新的replication方式基于global transaction identifiers(GTIDs),是事务的,并且不需要和log files、position进行交互,其大大简化了许多通用的replication任务。使用GTIDs的replication保证了source和replica的一致性,所有在source提交的事务都会在replica被应用。
|
- 新的replication方式基于global transaction identifiers(GTIDs),是事务的,并且不需要和log files、position进行交互,其大大简化了许多通用的replication任务。使用GTIDs的replication保证了source和replica的一致性,所有在source提交的事务都会在replica被应用。
|
||||||
|
|
||||||
mysql中的replication支持不同类型的同步。
|
mysql中的replication支持不同类型的同步。
|
||||||
- 原始的同步是单向、异步的复制,一个server作为source、其他一个或多个servers作为replicas。
|
- 原始的同步是单向、异步的复制,一个server作为source、其他一个或多个servers作为replicas。
|
||||||
- NDB Cluster中,支持synchronous replication
|
- NDB Cluster中,支持synchronous replication
|
||||||
- 在mysql 8.4中,支持了半同步复制,通过半同步复制,在source中执行的提交将会被阻塞,直到至少一个replica收到transaction并对transaction进行log event,且向source发送ack
|
- 在mysql 8.4中,支持了半同步复制,通过半同步复制,在source中执行的提交将会被阻塞,直到至少一个replica收到transaction并对transaction进行log event,且向source发送ack
|
||||||
- mysql 8.4同样支持delayed replication,使得replica故意落后于source至少指定的时间
|
- mysql 8.4同样支持delayed replication,使得replica故意落后于source至少指定的时间
|
||||||
|
|
||||||
## Configuration Replication
|
## Configuration Replication
|
||||||
### binary log file position based replication configuration overview
|
### binary log file position based replication configuration overview
|
||||||
在该section中,会描述mysql servers间基于binary log file position的replication方案。(source会将database的writes和updates操作以events的形式写入到binary log中)。根据database记录的变更,binary log中的信息将会以不同的logging format存储。replicas可以被配置,从source的binary log读取events,并且在replica本地的binary log中执行时间。
|
在该section中,会描述mysql servers间基于binary log file position的replication方案。(source会将database的writes和updates操作以events的形式写入到binary log中)。根据database记录的变更,binary log中的信息将会以不同的logging format存储。replicas可以被配置,从source的binary log读取events,并且在replica本地的binary log中执行时间。
|
||||||
|
|
||||||
每个replica都会接收binary log的完整副本内容,并由replica来决定binary log中哪些statements应当被执行。除非你显式指定,否则binary log中所有的events都会在replica上被执行。如果需要,你可以对replica进行配置,仅处理应用于特定databases、tables的events。
|
每个replica都会接收binary log的完整副本内容,并由replica来决定binary log中哪些statements应当被执行。除非你显式指定,否则binary log中所有的events都会在replica上被执行。如果需要,你可以对replica进行配置,仅处理应用于特定databases、tables的events。
|
||||||
|
|
||||||
每个replica都会记录二进制日志的坐标:其已经从source读取并处理的file name和文件中的position。这代表多个replicas可以连接到source,并执行相同binary log的不同部分。由于该过程受replicas控制,故而独立的replicas可以和source建立连接、取消连接,并且不会影响到source的操作。并且,每个replica记录了binary log的当前position,replica可以断开连接、重新连接并重启之前的过程。
|
每个replica都会记录二进制日志的坐标:其已经从source读取并处理的file name和文件中的position。这代表多个replicas可以连接到source,并执行相同binary log的不同部分。由于该过程受replicas控制,故而独立的replicas可以和source建立连接、取消连接,并且不会影响到source的操作。并且,每个replica记录了binary log的当前position,replica可以断开连接、重新连接并重启之前的过程。
|
||||||
|
|
||||||
source和每个replica都配置了unique ID(使用`server_id` system variable),除此之外,每个replica必须配置如下信息:
|
source和每个replica都配置了unique ID(使用`server_id` system variable),除此之外,每个replica必须配置如下信息:
|
||||||
- source's host name
|
- source's host name
|
||||||
- source's log file name
|
- source's log file name
|
||||||
- position of source's file
|
- position of source's file
|
||||||
|
|
||||||
这些可以在replica的mysql session内通过`CHANGE REPLICATION SOURCE TO`语句来管理,并且这些信息存储在replica的connection metadata repository中。
|
这些可以在replica的mysql session内通过`CHANGE REPLICATION SOURCE TO`语句来管理,并且这些信息存储在replica的connection metadata repository中。
|
||||||
|
|
||||||
### Replication with Global Transaction Identifiers
|
### Replication with Global Transaction Identifiers
|
||||||
在该章节中,描述了使用global transaction identifiers(GTIDs)的transaction-based replication。当使用GTIDs时,每个在source上提交的事务都可以被标识和追踪,并可以被任一replica应用。
|
在该章节中,描述了使用global transaction identifiers(GTIDs)的transaction-based replication。当使用GTIDs时,每个在source上提交的事务都可以被标识和追踪,并可以被任一replica应用。
|
||||||
|
|
||||||
在使用GTIDs时,启动新replica或failover to a new source时并不需要参照log files或file position。由于GTIDs时完全transaction-based的,其更容易判断是否source和replicas一致,只要在source中提交的事务全部也都在replica上提交,那么source和replica则是保证一致的。
|
在使用GTIDs时,启动新replica或failover to a new source时并不需要参照log files或file position。由于GTIDs时完全transaction-based的,其更容易判断是否source和replicas一致,只要在source中提交的事务全部也都在replica上提交,那么source和replica则是保证一致的。
|
||||||
|
|
||||||
在使用GTIDs时,可以选择是statement-based的还是row-based的,推荐使用row-based format。
|
在使用GTIDs时,可以选择是statement-based的还是row-based的,推荐使用row-based format。
|
||||||
|
|
||||||
GTIDs在source和replica都是持久化的。总是可以通过检测binary log来判断是否source中的任一事务是否在replica上被应用。此外,一旦给定GTID的事务在给定server上被提交,那么后续任一事务如果拥有相同的GTID,其都会被server忽略。因此,在source上被提交的事务可以在replica上应用多次,冗余的应用会被忽略,其可以保证数据的一致性。
|
GTIDs在source和replica都是持久化的。总是可以通过检测binary log来判断是否source中的任一事务是否在replica上被应用。此外,一旦给定GTID的事务在给定server上被提交,那么后续任一事务如果拥有相同的GTID,其都会被server忽略。因此,在source上被提交的事务可以在replica上应用多次,冗余的应用会被忽略,其可以保证数据的一致性。
|
||||||
|
|
||||||
#### GTID Format and Storage
|
#### GTID Format and Storage
|
||||||
一个global transation identifier(GTID)是一个唯一标识符,该标识符的创建并和`source上提交的每一个事务`进行关联。GTID不仅在创建其的server上是唯一的,并且在给定replication拓扑的所有servers间是唯一的。
|
一个global transation identifier(GTID)是一个唯一标识符,该标识符的创建并和`source上提交的每一个事务`进行关联。GTID不仅在创建其的server上是唯一的,并且在给定replication拓扑的所有servers间是唯一的。
|
||||||
|
|
||||||
GTID的分配区分了client trasactions(在source上提交的事务)以及replicated transactions(在replica上reproduced的事务)。当client transaction在source上提交时,如果transaction被写入到binary log中,其会被分配一个新的GTID。client transactions将会被保证单调递增,并且生成的编号之间不会存在间隙。`如果client transaction没有被写入到binary log,那么其在source中并不会被分配GTID`。
|
GTID的分配区分了client trasactions(在source上提交的事务)以及replicated transactions(在replica上reproduced的事务)。当client transaction在source上提交时,如果transaction被写入到binary log中,其会被分配一个新的GTID。client transactions将会被保证单调递增,并且生成的编号之间不会存在间隙。`如果client transaction没有被写入到binary log,那么其在source中并不会被分配GTID`。
|
||||||
|
|
||||||
Replicated transaction将会使用`事务被source server分配的GTID`。在replicated transaction开始执行前,GTID就已经存在,并且,即使replicated transaction没有写入到replica的binary log中或是被replica过滤,该GTID也会被持久化。`mysql.gtid_executed` system table将会被用于保存`应用到给定server的所有事务的GTID,但是,已经存储到当前active binary log file的除外`。
|
Replicated transaction将会使用`事务被source server分配的GTID`。在replicated transaction开始执行前,GTID就已经存在,并且,即使replicated transaction没有写入到replica的binary log中或是被replica过滤,该GTID也会被持久化。`mysql.gtid_executed` system table将会被用于保存`应用到给定server的所有事务的GTID,但是,已经存储到当前active binary log file的除外`。
|
||||||
|
|
||||||
> `active binary log file`中的gtid最终也会被写入到`gtid_executed`表中,但是,对于不同的存储引擎,写入时机可能不同。对于innodb而言,在事务提交时就会写入gtid_executed表,而对于其他存储引擎而言,则会在binary log发生rotation/server shutdown后才会将active binary log中尚未写入的GTIDs写入到`mysql.gtid_executed`表
|
> `active binary log file`中的gtid最终也会被写入到`gtid_executed`表中,但是,对于不同的存储引擎,写入时机可能不同。对于innodb而言,在事务提交时就会写入gtid_executed表,而对于其他存储引擎而言,则会在binary log发生rotation/server shutdown后才会将active binary log中尚未写入的GTIDs写入到`mysql.gtid_executed`表
|
||||||
|
|
||||||
GTIDs的auto-skip功能代表一个在source上提交的事务最多只能在replica上应用一次,这有助于保证一致性。一旦拥有给定GTID的事务在给定server上被提交,任何后续执行的事务如果拥有相同的GTID,都会被server忽略。并不会抛出异常,并且事务中的statements都不会被实际执行。
|
GTIDs的auto-skip功能代表一个在source上提交的事务最多只能在replica上应用一次,这有助于保证一致性。一旦拥有给定GTID的事务在给定server上被提交,任何后续执行的事务如果拥有相同的GTID,都会被server忽略。并不会抛出异常,并且事务中的statements都不会被实际执行。
|
||||||
|
|
||||||
如果拥有给定GTID的事务在server上已经开始执行,但是尚未提交或回滚,那么任何尝试开启一个`拥有相同GTID事务的操作都会被阻塞`。该server并不会开始执行拥有相同GTID的事务,也不会将控制权交还给client。一旦第一个事务提交或回滚,那么被阻塞的事务就可以开始执行。如果第一次执行被回滚,那么被阻塞事务可以实际执行;如果第一个事务成功提交,那么被阻塞事务并不会被实际执行,而是会被自动跳过。
|
如果拥有给定GTID的事务在server上已经开始执行,但是尚未提交或回滚,那么任何尝试开启一个`拥有相同GTID事务的操作都会被阻塞`。该server并不会开始执行拥有相同GTID的事务,也不会将控制权交还给client。一旦第一个事务提交或回滚,那么被阻塞的事务就可以开始执行。如果第一次执行被回滚,那么被阻塞事务可以实际执行;如果第一个事务成功提交,那么被阻塞事务并不会被实际执行,而是会被自动跳过。
|
||||||
|
|
||||||
GTID的表示形式如下:
|
GTID的表示形式如下:
|
||||||
```
|
```
|
||||||
GTID = source_id:transaction_id
|
GTID = source_id:transaction_id
|
||||||
```
|
```
|
||||||
- `source_id`表示了originating server,通常为source的`server_uuid`
|
- `source_id`表示了originating server,通常为source的`server_uuid`
|
||||||
- `transaction_id`则是一个由`transaction在source上提交顺序`决定的序列号。例如,第一个被提交的事务,其transaction_id为1;而第十个被提交的事务,其transaction_id则是为10.
|
- `transaction_id`则是一个由`transaction在source上提交顺序`决定的序列号。例如,第一个被提交的事务,其transaction_id为1;而第十个被提交的事务,其transaction_id则是为10.
|
||||||
- 在GTID中,transaction_id部分的值不可能为0
|
- 在GTID中,transaction_id部分的值不可能为0
|
||||||
|
|
||||||
例如,在UUID为`3E11FA47-71CA-11E1-9E33-C80AA9429562`上的server提交的第23个事务,其GTID为
|
例如,在UUID为`3E11FA47-71CA-11E1-9E33-C80AA9429562`上的server提交的第23个事务,其GTID为
|
||||||
```
|
```
|
||||||
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
|
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
|
||||||
```
|
```
|
||||||
|
|
||||||
在GTID中,序列号的上限值为`2^63 - 1, or 9223372036854775807`(signed 64-bit integer)。如果server运行时超过GTIDs,其将执行`binlog_error_action`指定的行为。当server接近该限制时,会发出一个warning message。
|
在GTID中,序列号的上限值为`2^63 - 1, or 9223372036854775807`(signed 64-bit integer)。如果server运行时超过GTIDs,其将执行`binlog_error_action`指定的行为。当server接近该限制时,会发出一个warning message。
|
||||||
|
|
||||||
在mysql 8.4中,也支持tagged GTIDs,一个tagged GTID由三部分组成,通过`:`进行分隔,示例如下所示:
|
在mysql 8.4中,也支持tagged GTIDs,一个tagged GTID由三部分组成,通过`:`进行分隔,示例如下所示:
|
||||||
```
|
```
|
||||||
GTID = source_id:tag:transaction_id
|
GTID = source_id:tag:transaction_id
|
||||||
```
|
```
|
||||||
|
|
||||||
在该示例中,`source_id`和`transaction_id`的含义和先前相同,`tag`则是一个用户自定义的字符串,用于表示`specific group of transactions`。
|
在该示例中,`source_id`和`transaction_id`的含义和先前相同,`tag`则是一个用户自定义的字符串,用于表示`specific group of transactions`。
|
||||||
|
|
||||||
例如,在UUID为`ed102faf-eb00-11eb-8f20-0c5415bfaa1d`的server上第117个提交的tag为`Domain_1`的事务,其GTID为
|
例如,在UUID为`ed102faf-eb00-11eb-8f20-0c5415bfaa1d`的server上第117个提交的tag为`Domain_1`的事务,其GTID为
|
||||||
```
|
```
|
||||||
ed102faf-eb00-11eb-8f20-0c5415bfaa1d:Domain_1:117
|
ed102faf-eb00-11eb-8f20-0c5415bfaa1d:Domain_1:117
|
||||||
```
|
```
|
||||||
|
|
||||||
事务的GTID会展示在`mysqlbinlog`的输出中,用于分辨`performance schema replication status tables`中独立的事务,例如`replication_applier_status_by_worker`表。
|
事务的GTID会展示在`mysqlbinlog`的输出中,用于分辨`performance schema replication status tables`中独立的事务,例如`replication_applier_status_by_worker`表。
|
||||||
|
|
||||||
`gtid_next` system variable的值是单个GTID。
|
`gtid_next` system variable的值是单个GTID。
|
||||||
|
|
||||||
##### GTID Sets
|
##### GTID Sets
|
||||||
一个GTID set由`一个或多个GTIDs`或`GTIDs`范围构成。`gtid_executed`或`gtid_purged` system variables存储的就是GTID sets。`START REPLICA`选项`UNTIL SQL_BEFORE_GTIDS`和`UNTIL SQL_AFTER_GTIDS`可令replica在处理事务时,`最多只处理到GTID set中的第一个GTID`或`在处理完GTID set中的最后一个GTID后停止`。内置的`GTID_SUBSET()`和`GTID_SUBTRACT()`函数需要`GTID sets`作为输入。
|
一个GTID set由`一个或多个GTIDs`或`GTIDs`范围构成。`gtid_executed`或`gtid_purged` system variables存储的就是GTID sets。`START REPLICA`选项`UNTIL SQL_BEFORE_GTIDS`和`UNTIL SQL_AFTER_GTIDS`可令replica在处理事务时,`最多只处理到GTID set中的第一个GTID`或`在处理完GTID set中的最后一个GTID后停止`。内置的`GTID_SUBSET()`和`GTID_SUBTRACT()`函数需要`GTID sets`作为输入。
|
||||||
|
|
||||||
在相同server上的GTIDs范围可以按照如下形式来表示:
|
在相同server上的GTIDs范围可以按照如下形式来表示:
|
||||||
```
|
```
|
||||||
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
|
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
|
||||||
```
|
```
|
||||||
上述示例表示在uuid为`3E11FA47-71CA-11E1-9E33-C80AA9429562`的server上提交的顺序为`1~5`之间的事务。
|
上述示例表示在uuid为`3E11FA47-71CA-11E1-9E33-C80AA9429562`的server上提交的顺序为`1~5`之间的事务。
|
||||||
|
|
||||||
相同server上的多个single GTIDs或ranges of GTIDs可以通过如下形式来表示
|
相同server上的多个single GTIDs或ranges of GTIDs可以通过如下形式来表示
|
||||||
```
|
```
|
||||||
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3:11:47-49
|
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3:11:47-49
|
||||||
```
|
```
|
||||||
|
|
||||||
GTID set可以包含任意`single GTIDs`和`GTIDs range`的组合,也可以包含来自不同server的GTIDs。如下实例中展示了`gtid_executed` system variable中存储的GTID set,代表replica中应用了来自超过一个source的事务:
|
GTID set可以包含任意`single GTIDs`和`GTIDs range`的组合,也可以包含来自不同server的GTIDs。如下实例中展示了`gtid_executed` system variable中存储的GTID set,代表replica中应用了来自超过一个source的事务:
|
||||||
```
|
```
|
||||||
2174B383-5441-11E8-B90A-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19
|
2174B383-5441-11E8-B90A-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19
|
||||||
```
|
```
|
||||||
当GTID set从server variables中返回时,UUID按照字母排序返回,而序列号间区间则是合并后按照升序排列。
|
当GTID set从server variables中返回时,UUID按照字母排序返回,而序列号间区间则是合并后按照升序排列。
|
||||||
|
|
||||||
当构建GTID set时,用户自定义tag也会被作为UUID的一部分,这代表来自相同server且tag相同的多个GTIDs可以被包含在一个表达式中,如下所示:
|
当构建GTID set时,用户自定义tag也会被作为UUID的一部分,这代表来自相同server且tag相同的多个GTIDs可以被包含在一个表达式中,如下所示:
|
||||||
```
|
```
|
||||||
3E11FA47-71CA-11E1-9E33-C80AA9429562:Domain_1:1-3:11:47-49
|
3E11FA47-71CA-11E1-9E33-C80AA9429562:Domain_1:1-3:11:47-49
|
||||||
```
|
```
|
||||||
来源相同server,但是tags不同的GTIDs表示方式如下:
|
来源相同server,但是tags不同的GTIDs表示方式如下:
|
||||||
```
|
```
|
||||||
3E11FA47-71CA-11E1-9E33-C80AA9429562:Domain_1:1-3:15-21, 3E11FA47-71CA-11E1-9E33-C80AA9429562:Domain_2:8-52
|
3E11FA47-71CA-11E1-9E33-C80AA9429562:Domain_1:1-3:15-21, 3E11FA47-71CA-11E1-9E33-C80AA9429562:Domain_2:8-52
|
||||||
```
|
```
|
||||||
|
|
||||||
GTID set的完整语法如下所示:
|
GTID set的完整语法如下所示:
|
||||||
```
|
```
|
||||||
gtid_set:
|
gtid_set:
|
||||||
uuid_set [, uuid_set] ...
|
uuid_set [, uuid_set] ...
|
||||||
| ''
|
| ''
|
||||||
|
|
||||||
uuid_set:
|
uuid_set:
|
||||||
uuid:[tag:]interval[:interval]...
|
uuid:[tag:]interval[:interval]...
|
||||||
|
|
||||||
uuid:
|
uuid:
|
||||||
hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh
|
hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh
|
||||||
|
|
||||||
h:
|
h:
|
||||||
[0-9|A-F]
|
[0-9|A-F]
|
||||||
|
|
||||||
tag:
|
tag:
|
||||||
[a-z_][a-z0-9_]{0,31}
|
[a-z_][a-z0-9_]{0,31}
|
||||||
|
|
||||||
interval:
|
interval:
|
||||||
m[-n]
|
m[-n]
|
||||||
|
|
||||||
(m >= 1; n > m)
|
(m >= 1; n > m)
|
||||||
```
|
```
|
||||||
##### msyql.gtid_executed
|
##### msyql.gtid_executed
|
||||||
GTIDs被存储在`mysql.gtid_executed`表中,该表中的行用于表示GTID或GTID set,行包含信息如下
|
GTIDs被存储在`mysql.gtid_executed`表中,该表中的行用于表示GTID或GTID set,行包含信息如下
|
||||||
- source server的uuid
|
- source server的uuid
|
||||||
- 用户自定义的tag
|
- 用户自定义的tag
|
||||||
- starting transaction IDs of the set
|
- starting transaction IDs of the set
|
||||||
- ending transaction IDs of the set
|
- ending transaction IDs of the set
|
||||||
|
|
||||||
如果行代表single GTID,那么最后两个字段的值相同。
|
如果行代表single GTID,那么最后两个字段的值相同。
|
||||||
|
|
||||||
`mysql.gtid_executed`表在mysql server安装或升级时会被自动创建,其表结构如下:
|
`mysql.gtid_executed`表在mysql server安装或升级时会被自动创建,其表结构如下:
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE gtid_executed (
|
CREATE TABLE gtid_executed (
|
||||||
source_uuid CHAR(36) NOT NULL,
|
source_uuid CHAR(36) NOT NULL,
|
||||||
interval_start BIGINT NOT NULL,
|
interval_start BIGINT NOT NULL,
|
||||||
interval_end BIGINT NOT NULL,
|
interval_end BIGINT NOT NULL,
|
||||||
gtid_tag CHAR(32) NOT NULL,
|
gtid_tag CHAR(32) NOT NULL,
|
||||||
PRIMARY KEY (source_uuid, gtid_tag, interval_start)
|
PRIMARY KEY (source_uuid, gtid_tag, interval_start)
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`mysql.gtid_executed`用于mysql server内部使用,其允许replica在binary logging被禁用的情况下使用GTIDs,其也可以在binary logs丢失时保留GTID的状态。如果执行`RESET BINARY LOGS AND GTIDS`,那么`mysql.gtid_executed`表将会被清空。
|
`mysql.gtid_executed`用于mysql server内部使用,其允许replica在binary logging被禁用的情况下使用GTIDs,其也可以在binary logs丢失时保留GTID的状态。如果执行`RESET BINARY LOGS AND GTIDS`,那么`mysql.gtid_executed`表将会被清空。
|
||||||
|
|
||||||
只有当`gtid_mode`被设置为`ON`或`ON_PERMISSIVE`时,GTIDs才会被存储到mysql.gtid_executed中。如果binary logging被禁用,或者`log_replica_updates`被禁用,server在事务提交时将会把属于个各事务的GTID和事务一起存储到buffer中,并且background threads将会周期性将buffer中的内容以entries的形式添加到`mysql.gtid_executed`表中。
|
只有当`gtid_mode`被设置为`ON`或`ON_PERMISSIVE`时,GTIDs才会被存储到mysql.gtid_executed中。如果binary logging被禁用,或者`log_replica_updates`被禁用,server在事务提交时将会把属于个各事务的GTID和事务一起存储到buffer中,并且background threads将会周期性将buffer中的内容以entries的形式添加到`mysql.gtid_executed`表中。
|
||||||
|
|
||||||
对于innodb存储引擎而言,如果binary logging被启用,server更新`mysql.gtid_executed`表的方式将会和`binary logging或replica update logging被启用`时一样,都会在每个事务提交时存储GTID。对于其他存储引擎,则是在binary log rotation发生时或server shut down时更新`mysql.gtid_executed`表的内容。
|
对于innodb存储引擎而言,如果binary logging被启用,server更新`mysql.gtid_executed`表的方式将会和`binary logging或replica update logging被启用`时一样,都会在每个事务提交时存储GTID。对于其他存储引擎,则是在binary log rotation发生时或server shut down时更新`mysql.gtid_executed`表的内容。
|
||||||
|
|
||||||
如果mysql.gtid_executed表无法被写访问,并且binary log file因`reaching the maximum file size`之外的任何理由被rotated,那么current binary log file将仍被使用。并且,当client发起rotation时将会返回错误信息,并且server将会输出warning日志。如果`mysql.gtid_executed`无法被写访问,并且binary log单个文件大小达到`max_binlog_size`,那么server将会根据`binlog_error_action`设置来执行操作。如果`IGNORE_ERROR`被设置,那么server将会输出error到日志,并且binary logging将会被停止;如果`ABORT_SERVER`被设置,那么server将会shutdown。
|
如果mysql.gtid_executed表无法被写访问,并且binary log file因`reaching the maximum file size`之外的任何理由被rotated,那么current binary log file将仍被使用。并且,当client发起rotation时将会返回错误信息,并且server将会输出warning日志。如果`mysql.gtid_executed`无法被写访问,并且binary log单个文件大小达到`max_binlog_size`,那么server将会根据`binlog_error_action`设置来执行操作。如果`IGNORE_ERROR`被设置,那么server将会输出error到日志,并且binary logging将会被停止;如果`ABORT_SERVER`被设置,那么server将会shutdown。
|
||||||
|
|
||||||
> 因为写入到active binary log的GTIDs最终也要被写入`mysql.gtid_executed`表,但是该表若当前不可写访问,那么此时将无法触发`binary log rotation`。
|
> 因为写入到active binary log的GTIDs最终也要被写入`mysql.gtid_executed`表,但是该表若当前不可写访问,那么此时将无法触发`binary log rotation`。
|
||||||
>
|
>
|
||||||
> MySQL.gtid_executed中缺失的GTIDs必须包含在active binary log file中,如果log file触发rotation,但是无法向mysql.gtid_executed中写入数据,那么rotation是不被允许的。
|
> MySQL.gtid_executed中缺失的GTIDs必须包含在active binary log file中,如果log file触发rotation,但是无法向mysql.gtid_executed中写入数据,那么rotation是不被允许的。
|
||||||
|
|
||||||
|
|
||||||
##### mysql.gtid_executed table compression
|
##### mysql.gtid_executed table compression
|
||||||
随着时间的推移,mysql.gtid_executed表会填满大量行,行数据代表独立的GTID,示例如下:
|
随着时间的推移,mysql.gtid_executed表会填满大量行,行数据代表独立的GTID,示例如下:
|
||||||
```
|
```
|
||||||
+--------------------------------------+----------------+--------------+----------+
|
+--------------------------------------+----------------+--------------+----------+
|
||||||
| source_uuid | interval_start | interval_end | gtid_tag |
|
| source_uuid | interval_start | interval_end | gtid_tag |
|
||||||
|--------------------------------------+----------------+--------------|----------+
|
|--------------------------------------+----------------+--------------|----------+
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 31 | 31 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 31 | 31 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 32 | 32 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 32 | 32 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 33 | 33 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 33 | 33 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 34 | 34 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 34 | 34 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 35 | 35 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 35 | 35 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 36 | 36 | Domain_2 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 36 | 36 | Domain_2 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37 | 37 | Domain_2 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37 | 37 | Domain_2 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 38 | 38 | Domain_2 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 38 | 38 | Domain_2 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 39 | 39 | Domain_2 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 39 | 39 | Domain_2 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 40 | 40 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 40 | 40 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 41 | 41 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 41 | 41 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 42 | 42 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 42 | 42 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 43 | 43 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 43 | 43 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 44 | 44 | Domain_2 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 44 | 44 | Domain_2 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 45 | 45 | Domain_2 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 45 | 45 | Domain_2 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 46 | 46 | Domain_2 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 46 | 46 | Domain_2 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 47 | 47 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 47 | 47 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 48 | 48 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 48 | 48 | Domain_1 |
|
||||||
```
|
```
|
||||||
|
|
||||||
为了节省空间,可以对gtid_executed表周期性的进行压缩,将多个`single GTID`替换为单个`GTID set`,压缩后的数据如下;
|
为了节省空间,可以对gtid_executed表周期性的进行压缩,将多个`single GTID`替换为单个`GTID set`,压缩后的数据如下;
|
||||||
```
|
```
|
||||||
+--------------------------------------+----------------+--------------+----------+
|
+--------------------------------------+----------------+--------------+----------+
|
||||||
| source_uuid | interval_start | interval_end | gtid_tag |
|
| source_uuid | interval_start | interval_end | gtid_tag |
|
||||||
|--------------------------------------+----------------+--------------|----------+
|
|--------------------------------------+----------------+--------------|----------+
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 31 | 35 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 31 | 35 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 36 | 39 | Domain_2 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 36 | 39 | Domain_2 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 40 | 43 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 40 | 43 | Domain_1 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 44 | 46 | Domain_2 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 44 | 46 | Domain_2 |
|
||||||
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 47 | 48 | Domain_1 |
|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 47 | 48 | Domain_1 |
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
server可通过名为`thread/sql/compress_gtid_table`的前台线程来执行gtid_executed表的压缩操作,该线程并不会在`show processlist`的输出中被列出,但是可以通过查询`threads`表来查看,示例如下:
|
server可通过名为`thread/sql/compress_gtid_table`的前台线程来执行gtid_executed表的压缩操作,该线程并不会在`show processlist`的输出中被列出,但是可以通过查询`threads`表来查看,示例如下:
|
||||||
```sql
|
```sql
|
||||||
mysql> SELECT * FROM performance_schema.threads WHERE NAME LIKE '%gtid%'\G
|
mysql> SELECT * FROM performance_schema.threads WHERE NAME LIKE '%gtid%'\G
|
||||||
*************************** 1. row ***************************
|
*************************** 1. row ***************************
|
||||||
THREAD_ID: 26
|
THREAD_ID: 26
|
||||||
NAME: thread/sql/compress_gtid_table
|
NAME: thread/sql/compress_gtid_table
|
||||||
TYPE: FOREGROUND
|
TYPE: FOREGROUND
|
||||||
PROCESSLIST_ID: 1
|
PROCESSLIST_ID: 1
|
||||||
PROCESSLIST_USER: NULL
|
PROCESSLIST_USER: NULL
|
||||||
PROCESSLIST_HOST: NULL
|
PROCESSLIST_HOST: NULL
|
||||||
PROCESSLIST_DB: NULL
|
PROCESSLIST_DB: NULL
|
||||||
PROCESSLIST_COMMAND: Daemon
|
PROCESSLIST_COMMAND: Daemon
|
||||||
PROCESSLIST_TIME: 1509
|
PROCESSLIST_TIME: 1509
|
||||||
PROCESSLIST_STATE: Suspending
|
PROCESSLIST_STATE: Suspending
|
||||||
PROCESSLIST_INFO: NULL
|
PROCESSLIST_INFO: NULL
|
||||||
PARENT_THREAD_ID: 1
|
PARENT_THREAD_ID: 1
|
||||||
ROLE: NULL
|
ROLE: NULL
|
||||||
INSTRUMENTED: YES
|
INSTRUMENTED: YES
|
||||||
HISTORY: YES
|
HISTORY: YES
|
||||||
CONNECTION_TYPE: NULL
|
CONNECTION_TYPE: NULL
|
||||||
THREAD_OS_ID: 18677
|
THREAD_OS_ID: 18677
|
||||||
```
|
```
|
||||||
当server启用了binary log时,上述压缩方式并不会被使用,`mysql.gtid_executed`在每次binary log rotation时会被压缩。但是,当binary logging被禁用时,`thread/sql/compress_gtid`线程处于sleep状态,每有一定数量的事务被执行时,线程会wake up并执行压缩操作。在table被压缩之前经过的事务数量,即压缩率,可由system variable `gtid_executed_compression_period`来进行控制。如果将值设置为0,代表该thread永远不会wake up。
|
当server启用了binary log时,上述压缩方式并不会被使用,`mysql.gtid_executed`在每次binary log rotation时会被压缩。但是,当binary logging被禁用时,`thread/sql/compress_gtid`线程处于sleep状态,每有一定数量的事务被执行时,线程会wake up并执行压缩操作。在table被压缩之前经过的事务数量,即压缩率,可由system variable `gtid_executed_compression_period`来进行控制。如果将值设置为0,代表该thread永远不会wake up。
|
||||||
|
|
||||||
相比于其他存储引擎,innodb事务写入`mysql.gtid_executed`的过程有所不同,在innodb存储引擎中,过程通过线程`innodb/clone_gtid_thread`来执行。此GTID持久化线程将会分组收集GTIDs,并将其刷新到`mysql.gtid_executed`表中,并对table进行压缩。如果server中既包含innodb事务,又包含non-innodb事务,那么由`compress_gtid_table`线程执行的压缩操作将会干扰`clone_gtid_thread`的工作,并对其效率进行显著下降。为此,在此场景下更推荐将`gtid_executed_compression_period`设置为0,故而`compress_gtid_table`线程将永远不被激活。
|
相比于其他存储引擎,innodb事务写入`mysql.gtid_executed`的过程有所不同,在innodb存储引擎中,过程通过线程`innodb/clone_gtid_thread`来执行。此GTID持久化线程将会分组收集GTIDs,并将其刷新到`mysql.gtid_executed`表中,并对table进行压缩。如果server中既包含innodb事务,又包含non-innodb事务,那么由`compress_gtid_table`线程执行的压缩操作将会干扰`clone_gtid_thread`的工作,并对其效率进行显著下降。为此,在此场景下更推荐将`gtid_executed_compression_period`设置为0,故而`compress_gtid_table`线程将永远不被激活。
|
||||||
|
|
||||||
`gtid_executed_compression_period`的默认值为0,且所有事务不论其所属存储引擎,都会被`clone_gitid_thread`写入到`mysql.gtid_exec uted`中。
|
`gtid_executed_compression_period`的默认值为0,且所有事务不论其所属存储引擎,都会被`clone_gitid_thread`写入到`mysql.gtid_exec uted`中。
|
||||||
|
|
||||||
当server实例启动后,如果`gtid_executed_compression_preiod`被设置为非0值,并且`compress_gtid_table`线程也启动,在多数server配置中,将会对`msyql.gtid_executed`表执行显式压缩。压缩通过线程的启动触发。
|
当server实例启动后,如果`gtid_executed_compression_preiod`被设置为非0值,并且`compress_gtid_table`线程也启动,在多数server配置中,将会对`msyql.gtid_executed`表执行显式压缩。压缩通过线程的启动触发。
|
||||||
|
|
||||||
#### GTID生命周期
|
#### GTID生命周期
|
||||||
GTID生命周期由如下步骤组成:
|
GTID生命周期由如下步骤组成:
|
||||||
1. 事务在source上被执行并提交,client transaction将会被分配GTID,GTID由`source UUID`和`smallest nonzero transaction sequence number not yet used on this server`组成。GTID也会被写入到binary log中(在log中,GTID被写入在事务之前)。如果client transaction没有被写入binary log(例如,事务被过滤或事务为read-only),那么该事务不会被分配GTID
|
1. 事务在source上被执行并提交,client transaction将会被分配GTID,GTID由`source UUID`和`smallest nonzero transaction sequence number not yet used on this server`组成。GTID也会被写入到binary log中(在log中,GTID被写入在事务之前)。如果client transaction没有被写入binary log(例如,事务被过滤或事务为read-only),那么该事务不会被分配GTID
|
||||||
2. 如果为事务分配了GTID,那么在事务提交时GTID会被原子的持久化。在binary log中,GTID会被写入到事务开始的位置。不管何时,如果binary log发生rotation或server shutdown,server会将所有写入到binary log file中事务的GTIDs写入到`mysql.gtid_executed`表中
|
2. 如果为事务分配了GTID,那么在事务提交时GTID会被原子的持久化。在binary log中,GTID会被写入到事务开始的位置。不管何时,如果binary log发生rotation或server shutdown,server会将所有写入到binary log file中事务的GTIDs写入到`mysql.gtid_executed`表中
|
||||||
3. 如果为事务分配了GTID,那么GTID的外部化是`non-atomically`的(在事务提交后非常短的时间)。外部化过程会将GTID添加到`gtid_executed` system variable所代表的GTID set中(`@@GLOBAL.gtid_executed`)。该GTID set中包含`representation of the set of all committed GTID transactions`,并且在replication中会作为代表server state的token使用。
|
3. 如果为事务分配了GTID,那么GTID的外部化是`non-atomically`的(在事务提交后非常短的时间)。外部化过程会将GTID添加到`gtid_executed` system variable所代表的GTID set中(`@@GLOBAL.gtid_executed`)。该GTID set中包含`representation of the set of all committed GTID transactions`,并且在replication中会作为代表server state的token使用。
|
||||||
1. 当binary logging启用时,`gtid_executed` system variable代表的GTIDs set是已被应用事务的完整记录。但是`mysql.gtid_executed`表则并记录所有GTIDs,可能由部分GTIDs仍存在于active binary log file中尚未被写入到gtid_executed table
|
1. 当binary logging启用时,`gtid_executed` system variable代表的GTIDs set是已被应用事务的完整记录。但是`mysql.gtid_executed`表则并记录所有GTIDs,可能由部分GTIDs仍存在于active binary log file中尚未被写入到gtid_executed table
|
||||||
4. 在binary log data被转移到replica并存储在replica的relay log中后,replica会读取GTID的值,并且将其设置到`gtid_next` system variable中。这告知replica下一个事务将会使用`gtid_next`所代表的GTID。replica在session context中设置`gtid_next`
|
4. 在binary log data被转移到replica并存储在replica的relay log中后,replica会读取GTID的值,并且将其设置到`gtid_next` system variable中。这告知replica下一个事务将会使用`gtid_next`所代表的GTID。replica在session context中设置`gtid_next`
|
||||||
5. replica在处理事务前,会验证没有其他线程已经持有了`gtid_next`中GTID的所有权。通过该方法,replica可以保证该该GTID关联的事务在replica上没有被应用过,并且还能保证没有其他session已经读取该GTID但是尚未提交关联事务。故而,如果并发的尝试应用相同的事务,那么server只会让其中的一个运行。
|
5. replica在处理事务前,会验证没有其他线程已经持有了`gtid_next`中GTID的所有权。通过该方法,replica可以保证该该GTID关联的事务在replica上没有被应用过,并且还能保证没有其他session已经读取该GTID但是尚未提交关联事务。故而,如果并发的尝试应用相同的事务,那么server只会让其中的一个运行。
|
||||||
1. replica的`gtid_owned` system variable(`@@GLOBAL.gtid_owned`)代表了当前正在使用的每个GTID和拥有该GTID的线程ID。如果GTID已经被使用过,并不会抛出错误,`auto-skip`功能会忽略该事务
|
1. replica的`gtid_owned` system variable(`@@GLOBAL.gtid_owned`)代表了当前正在使用的每个GTID和拥有该GTID的线程ID。如果GTID已经被使用过,并不会抛出错误,`auto-skip`功能会忽略该事务
|
||||||
6. 如果GTID尚未被使用,那么replica将会对replicated transaction进行应用。因为`gtid_next`被设置为了`由source分配的GTID`,replica将不会尝试为事务分配新的GTID,而是直接使用存储在`gtid_next`中存储的GTID
|
6. 如果GTID尚未被使用,那么replica将会对replicated transaction进行应用。因为`gtid_next`被设置为了`由source分配的GTID`,replica将不会尝试为事务分配新的GTID,而是直接使用存储在`gtid_next`中存储的GTID
|
||||||
7. 如果replica上启用了binary logging,GTID将会在提交时被原子的持久化,写入到binary log中事务开始的位置。无论何时,如果binary log发生rotation或server shutdown,server会将`先前写入到binary log中事务的GTIDs`写入到`mysql.gtid_executed`表中
|
7. 如果replica上启用了binary logging,GTID将会在提交时被原子的持久化,写入到binary log中事务开始的位置。无论何时,如果binary log发生rotation或server shutdown,server会将`先前写入到binary log中事务的GTIDs`写入到`mysql.gtid_executed`表中
|
||||||
8. 如果replica禁用binary log,GTID将会原子的被持久化,直接被写入到`mysql.gtid_executed`表中。mysql会向事务中追加一个statement,并且将GTID插入到table中该操作是原子的,在该场景下,`mysql.gtid_executed`表记录了完整的`transactions applied on the replica`。
|
8. 如果replica禁用binary log,GTID将会原子的被持久化,直接被写入到`mysql.gtid_executed`表中。mysql会向事务中追加一个statement,并且将GTID插入到table中该操作是原子的,在该场景下,`mysql.gtid_executed`表记录了完整的`transactions applied on the replica`。
|
||||||
9. 在replicated transaction提交后很短的时间,GTID会被非原子的externalized,GTID会被添加到replica的`gtid_executed` system variable代表的GTIDs中。在source中,`gtid_executed` system variable包含了所有提交的GTID事务。
|
9. 在replicated transaction提交后很短的时间,GTID会被非原子的externalized,GTID会被添加到replica的`gtid_executed` system variable代表的GTIDs中。在source中,`gtid_executed` system variable包含了所有提交的GTID事务。
|
||||||
|
|
||||||
在source上被完全过滤的client transactions并不会被分配GTID,因此其不会被添加到`gtid_executed` system variable或被添加到`mysql.gtid_executed`表中。然而,replicated transaction中的GTIDs即使在replica被完全过滤,也会被持久化。
|
在source上被完全过滤的client transactions并不会被分配GTID,因此其不会被添加到`gtid_executed` system variable或被添加到`mysql.gtid_executed`表中。然而,replicated transaction中的GTIDs即使在replica被完全过滤,也会被持久化。
|
||||||
- 如果binary logging在replica开启,被过滤的事务将会作为gtid_log_event的形式被写入到binary log,后续跟着一个empty transaction,事务中仅包含BEGIN和COMMIT语句
|
- 如果binary logging在replica开启,被过滤的事务将会作为gtid_log_event的形式被写入到binary log,后续跟着一个empty transaction,事务中仅包含BEGIN和COMMIT语句
|
||||||
- 如果binary logging在replica被禁用,给过滤事务的GTID将会被写入到`mysql.gtid_executed`表
|
- 如果binary logging在replica被禁用,给过滤事务的GTID将会被写入到`mysql.gtid_executed`表
|
||||||
|
|
||||||
将filtered-out transactions的GTIDs保留,可以确保`mysql.gtid_executed`表和`gtid_executed`system variable中的GTIDs可以被压缩。同时其也能确保replica重新连接到source时,filtered-out transactions不会被重新获取
|
将filtered-out transactions的GTIDs保留,可以确保`mysql.gtid_executed`表和`gtid_executed`system variable中的GTIDs可以被压缩。同时其也能确保replica重新连接到source时,filtered-out transactions不会被重新获取
|
||||||
|
|
||||||
在多线程的replica上(`replica_parallel_workers > 0`),事务可以被并行的应用,故而replicated transactions可以以不同的顺序来提交(除非`replica_preserve_commit_order = 1`)。在并行提交时,`gtid_executed`system variable中的GTIDs将包含多个GTID ranges,多个范围之间存在空隙。在多线程replicas上,只有最近被应用的事务间才会存在空隙,并且会随着replication的进行而被填充。当replication threads通过`STOP REPLICA`停止时,这些空隙会被填补。当发生shutdown event时(server failure导致),此时replication 停止,空隙仍可能保留。
|
在多线程的replica上(`replica_parallel_workers > 0`),事务可以被并行的应用,故而replicated transactions可以以不同的顺序来提交(除非`replica_preserve_commit_order = 1`)。在并行提交时,`gtid_executed`system variable中的GTIDs将包含多个GTID ranges,多个范围之间存在空隙。在多线程replicas上,只有最近被应用的事务间才会存在空隙,并且会随着replication的进行而被填充。当replication threads通过`STOP REPLICA`停止时,这些空隙会被填补。当发生shutdown event时(server failure导致),此时replication 停止,空隙仍可能保留。
|
||||||
|
|
||||||
##### What changes are assign a GTID
|
##### What changes are assign a GTID
|
||||||
GTID生成的典型场景为`server为提交事务生成新的GTID`。然而,GTIDs可以被分配给除事务外的其他修改,且在某些场景下一个事务可以被分配多个GTIDs。
|
GTID生成的典型场景为`server为提交事务生成新的GTID`。然而,GTIDs可以被分配给除事务外的其他修改,且在某些场景下一个事务可以被分配多个GTIDs。
|
||||||
|
|
||||||
每个写入binary log的数据库修改(`DDL/DML`)都会被分配一个GTID。其包含了自动提交的变更、使用`BEGIN...COMMIT`的变更和使用`START TRANSACTION`的变更。一个GTID会被分配给数据库的`creation, alteration, deletion`操作,并且`non-table` database object例如`procedure, function, trigger, event, view, user, role, grant`的`creation, alteration, deletion`也会被分配GTID。
|
每个写入binary log的数据库修改(`DDL/DML`)都会被分配一个GTID。其包含了自动提交的变更、使用`BEGIN...COMMIT`的变更和使用`START TRANSACTION`的变更。一个GTID会被分配给数据库的`creation, alteration, deletion`操作,并且`non-table` database object例如`procedure, function, trigger, event, view, user, role, grant`的`creation, alteration, deletion`也会被分配GTID。
|
||||||
|
|
||||||
非事务更新和事务更新都会被分配`GTID`,额外的,对于非事务更新,如果在尝试写入binary log cahche时发生disk write failure,导致binary log中出现间隙,那么生成的日志事件将会被分配一个GTID。
|
非事务更新和事务更新都会被分配`GTID`,额外的,对于非事务更新,如果在尝试写入binary log cahche时发生disk write failure,导致binary log中出现间隙,那么生成的日志事件将会被分配一个GTID。
|
||||||
|
|
||||||
## Replication Implementation
|
## Replication Implementation
|
||||||
在replication的设计中,source server会追踪其binary log中所有对databases的修改。binary log中记录了自server启动时所有修改数据库结构或内容的事件。通常,`SELECT`语句将不会被记录,其并没有对数据库结构或内容造成修改。
|
在replication的设计中,source server会追踪其binary log中所有对databases的修改。binary log中记录了自server启动时所有修改数据库结构或内容的事件。通常,`SELECT`语句将不会被记录,其并没有对数据库结构或内容造成修改。
|
||||||
|
|
||||||
每个连接到source的replica都会请求binary log的副本,replica会从source处拉取数据,而不是source向replica推送数据。replica也会执行其从binary log收到的事件。`发生在source上的修改将会在replica上进行重现`。在重现过程中,会发生表创建、表结构修改、数据的新增/删除/修改等操作。
|
每个连接到source的replica都会请求binary log的副本,replica会从source处拉取数据,而不是source向replica推送数据。replica也会执行其从binary log收到的事件。`发生在source上的修改将会在replica上进行重现`。在重现过程中,会发生表创建、表结构修改、数据的新增/删除/修改等操作。
|
||||||
|
|
||||||
由于每个replica都是独立的,每个连接到source的replica,其对`source中binary log`内容的replaying都是独立的。此外,因为每个replica只通过请求source来接收binary log的拷贝,replica能够以其自身的节奏来读取和更新其数据副本,并且其能在不对source和其他replicas造成影响的条件下开启或停止replication过程。
|
由于每个replica都是独立的,每个连接到source的replica,其对`source中binary log`内容的replaying都是独立的。此外,因为每个replica只通过请求source来接收binary log的拷贝,replica能够以其自身的节奏来读取和更新其数据副本,并且其能在不对source和其他replicas造成影响的条件下开启或停止replication过程。
|
||||||
|
|
||||||
### Replication Formats
|
### Replication Formats
|
||||||
在binary log中,events根据其事件类型以不同的格式被记录。replication使用的foramts取决于事件被记录到source server的binary log中时所使用的foramt。binary log format和replciation过程中使用到的format,其关联关系如下:
|
在binary log中,events根据其事件类型以不同的格式被记录。replication使用的foramts取决于事件被记录到source server的binary log中时所使用的foramt。binary log format和replciation过程中使用到的format,其关联关系如下:
|
||||||
- 当使用statement-based binary logging时,source会将sql statements写入到binary log。从source到replica的replication将会在replica上执行该sql语句。这被称之为statement-based replication,关联了mysql statement-based binary logging format
|
- 当使用statement-based binary logging时,source会将sql statements写入到binary log。从source到replica的replication将会在replica上执行该sql语句。这被称之为statement-based replication,关联了mysql statement-based binary logging format
|
||||||
- 当使用row-based loggging时,source将会将`table rows如何变更`的事件写入到binary log中。在replica中,将会重现events对table rows所做的修改。则会被成为row-based replication
|
- 当使用row-based loggging时,source将会将`table rows如何变更`的事件写入到binary log中。在replica中,将会重现events对table rows所做的修改。则会被成为row-based replication
|
||||||
- `row-based logging`是默认的方法
|
- `row-based logging`是默认的方法
|
||||||
- 可以配置mysql使用`mix-format logging`,但使用`mix-format logging`时,将默认使用statement-based log。但是对于特定的语句,也取决于使用的存储引擎,在某些床惊吓log也会被自动切换到row-based。使用mixed format的replication被称之为mix-based replication或mix-format replication
|
- 可以配置mysql使用`mix-format logging`,但使用`mix-format logging`时,将默认使用statement-based log。但是对于特定的语句,也取决于使用的存储引擎,在某些床惊吓log也会被自动切换到row-based。使用mixed format的replication被称之为mix-based replication或mix-format replication
|
||||||
|
|
||||||
mysql server中的logging format通过`binlog_format` system variable来进行控制。该变量可以在session/global级别进行设置
|
mysql server中的logging format通过`binlog_format` system variable来进行控制。该变量可以在session/global级别进行设置
|
||||||
- 在将variable设置为session级别时,将仅会对当前session生效,并且仅持续到当前session结束
|
- 在将variable设置为session级别时,将仅会对当前session生效,并且仅持续到当前session结束
|
||||||
- 将variable设置为global级别时,该设置将会对`clients that connect after the change`生效,`但对于any current client sessions,包括.发出该修改请求的session都不生效`
|
- 将variable设置为global级别时,该设置将会对`clients that connect after the change`生效,`但对于any current client sessions,包括.发出该修改请求的session都不生效`
|
||||||
|
|
||||||
#### 使用statement-based和row-based replication的优缺点对比
|
#### 使用statement-based和row-based replication的优缺点对比
|
||||||
每个binary logging format都有优缺点。对大多数users,mixed replication format能够提供性能和数据完整性的最佳组合。
|
每个binary logging format都有优缺点。对大多数users,mixed replication format能够提供性能和数据完整性的最佳组合。
|
||||||
|
|
||||||
##### Advantages of statement-based replication
|
##### Advantages of statement-based replication
|
||||||
- 在使用statement-based格式时,会向log files中写入更少的数据。特别是在更新或删除大量行时,使用statement-based格式能够导致更少的空间占用。在从备份中获取和恢复时,其速度也更快
|
- 在使用statement-based格式时,会向log files中写入更少的数据。特别是在更新或删除大量行时,使用statement-based格式能够导致更少的空间占用。在从备份中获取和恢复时,其速度也更快
|
||||||
- log files包含所有造成修改的statements,可以被用于审核database
|
- log files包含所有造成修改的statements,可以被用于审核database
|
||||||
|
|
||||||
##### Disadvantages of statement-based replication
|
##### Disadvantages of statement-based replication
|
||||||
- 对于Statement-based replication而言,statements并不是安全的。并非所有对数据造成修改的statements都可以使用statement-based replication。在使用statement-based replication时,任何非确定性的行为都难以复制(例如在语句中包含随机函数等非确定性行为)
|
- 对于Statement-based replication而言,statements并不是安全的。并非所有对数据造成修改的statements都可以使用statement-based replication。在使用statement-based replication时,任何非确定性的行为都难以复制(例如在语句中包含随机函数等非确定性行为)
|
||||||
- 对于复杂语句,statement必须在实际对目标行执行修改前重新计算。而当使用row-based replication时,replica可以直接修改受影响行,而无需重新计算
|
- 对于复杂语句,statement必须在实际对目标行执行修改前重新计算。而当使用row-based replication时,replica可以直接修改受影响行,而无需重新计算
|
||||||
|
|
||||||
##### Advantages of row-based replication
|
##### Advantages of row-based replication
|
||||||
- 所有的修改可以被replicated,其是最安全的replication形式
|
- 所有的修改可以被replicated,其是最安全的replication形式
|
||||||
|
|
||||||
##### disadvantages of row-based replication
|
##### disadvantages of row-based replication
|
||||||
- 相比于statement-based replication,row-based replication通常会向log中ieur更多数据,特别是当statement操作大量行数据是
|
- 相比于statement-based replication,row-based replication通常会向log中ieur更多数据,特别是当statement操作大量行数据是
|
||||||
- 在replica并无法查看从source接收并执行的statements。可以通过`mysqlbinlog`的`--base64-output=DECODE-ROWS`和`--verbose`选项来查看数据变更
|
- 在replica并无法查看从source接收并执行的statements。可以通过`mysqlbinlog`的`--base64-output=DECODE-ROWS`和`--verbose`选项来查看数据变更
|
||||||
|
|
||||||
### Replay Log and Replication Metadata Repositories
|
### Replay Log and Replication Metadata Repositories
|
||||||
replica server会创建一系列仓库,其中存储在replication过程中使用的信息;
|
replica server会创建一系列仓库,其中存储在replication过程中使用的信息;
|
||||||
- `relay log`: 该日志被replication I/O线程写入,包含从source server的binary log读取的事务。relay log中记录的事务将会被replication SQL thread应用到replica
|
- `relay log`: 该日志被replication I/O线程写入,包含从source server的binary log读取的事务。relay log中记录的事务将会被replication SQL thread应用到replica
|
||||||
- `connection metadata repository`: 包含replication receiver thread连接到source server并从binary log获取事务时,需要的信息。connection metadata repository会被写入到`mysql.slave_master_info`中
|
- `connection metadata repository`: 包含replication receiver thread连接到source server并从binary log获取事务时,需要的信息。connection metadata repository会被写入到`mysql.slave_master_info`中
|
||||||
- `applier metadata repository`: 包含replication applier thread从relay log读取并应用事务时所需要的信息。applier metadata repository会被写入到`mysql.slave_relay_log_info`表中
|
- `applier metadata repository`: 包含replication applier thread从relay log读取并应用事务时所需要的信息。applier metadata repository会被写入到`mysql.slave_relay_log_info`表中
|
||||||
|
|
||||||
#### The Relay Log
|
#### The Relay Log
|
||||||
relay log和binary log类似,由一些`numbered files`构成,文件中包含`描述数据库变更的事件`。relay log还包含一个index file,其中记录了所有被使用的relay log files的名称。默认情况下,relay log files位于data directory中
|
relay log和binary log类似,由一些`numbered files`构成,文件中包含`描述数据库变更的事件`。relay log还包含一个index file,其中记录了所有被使用的relay log files的名称。默认情况下,relay log files位于data directory中
|
||||||
|
|
||||||
relay log files拥有和binary log相同的格式,也可以通过mysqlbinlog进行读取。如果使用了binary log transaction compression,那么写入relay log的事务payloads也会按照和binary log相同的方式被压缩。
|
relay log files拥有和binary log相同的格式,也可以通过mysqlbinlog进行读取。如果使用了binary log transaction compression,那么写入relay log的事务payloads也会按照和binary log相同的方式被压缩。
|
||||||
|
|
||||||
对于默认的replication channel,relay log file命名形式如下`host_name-relay-bin.nnnnnn`:
|
对于默认的replication channel,relay log file命名形式如下`host_name-relay-bin.nnnnnn`:
|
||||||
- `host_name`为replica server host的名称
|
- `host_name`为replica server host的名称
|
||||||
- `nnnnnn`是序列号,序列号从000001开始
|
- `nnnnnn`是序列号,序列号从000001开始
|
||||||
|
|
||||||
对于非默认的replication channels,默认的名称为`host_name-relay-bin-channel`:
|
对于非默认的replication channels,默认的名称为`host_name-relay-bin-channel`:
|
||||||
- `channel`为replciation channel的名称
|
- `channel`为replciation channel的名称
|
||||||
|
|
||||||
replica会使用index file来追踪当前在使用的relay log files。默认relay log index file的名称为`host_name-relay-bin.index`。
|
replica会使用index file来追踪当前在使用的relay log files。默认relay log index file的名称为`host_name-relay-bin.index`。
|
||||||
|
|
||||||
当如下条件下,replica server将会创建新的relay log file:
|
当如下条件下,replica server将会创建新的relay log file:
|
||||||
- 每次replication I/O thread开启时
|
- 每次replication I/O thread开启时
|
||||||
- 当logs被刷新时(例如,当执行`FLUSH LOGS`命令时)
|
- 当logs被刷新时(例如,当执行`FLUSH LOGS`命令时)
|
||||||
- 当当前relay log file的大小太大时,大小上限可以通过如下方式决定
|
- 当当前relay log file的大小太大时,大小上限可以通过如下方式决定
|
||||||
- 如果`max_relay_log_size`的大小大于0,那么其就是relay log file的最大大小
|
- 如果`max_relay_log_size`的大小大于0,那么其就是relay log file的最大大小
|
||||||
- 如果`max_relay_log_size`为0,那么relay log file的最大大小由`max_binlog_size`决定
|
- 如果`max_relay_log_size`为0,那么relay log file的最大大小由`max_binlog_size`决定
|
||||||
|
|
||||||
replication sql thread在其执行完文件中所有events之后,都不再需要该文件,被执行完的relay log file都会被自动删除。目前没有显式的机制来删除relay logs,relay log的删除由replciation sql thread来处理。但是,`FLUSH LOGS`可以针对relay logs进行rotation。
|
replication sql thread在其执行完文件中所有events之后,都不再需要该文件,被执行完的relay log file都会被自动删除。目前没有显式的机制来删除relay logs,relay log的删除由replciation sql thread来处理。但是,`FLUSH LOGS`可以针对relay logs进行rotation。
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
# Spring Cloud简介
|
# Spring Cloud简介
|
||||||
## eureka
|
## eureka
|
||||||
eureka是由netflix公司开源的一个服务注册与发现组件。eureka和其他一些同样由netflix公司开源的组建一起被整合为spring cloud netflix模块。
|
eureka是由netflix公司开源的一个服务注册与发现组件。eureka和其他一些同样由netflix公司开源的组建一起被整合为spring cloud netflix模块。
|
||||||
### eureka和zookeeper的区别
|
### eureka和zookeeper的区别
|
||||||
#### CAP原则
|
#### CAP原则
|
||||||
CAP原则指的是在一个分布式系统中,一致性(Consistency)、可用性(Aailability)和分区容错性(Partition Tolerance),三者中最多只能实现两者,无法实现三者兼顾。
|
CAP原则指的是在一个分布式系统中,一致性(Consistency)、可用性(Aailability)和分区容错性(Partition Tolerance),三者中最多只能实现两者,无法实现三者兼顾。
|
||||||
- C:一致性表示分布式系统中,不同节点中的数据都要相同
|
- C:一致性表示分布式系统中,不同节点中的数据都要相同
|
||||||
- A:可用性代表可以允许某一段时间内分布式系统中不同节点的数据可以不同,只要分布式系统能够保证最终数据的一致性。中途,允许分布式系统中的节点数据存在不一致的情形
|
- A:可用性代表可以允许某一段时间内分布式系统中不同节点的数据可以不同,只要分布式系统能够保证最终数据的一致性。中途,允许分布式系统中的节点数据存在不一致的情形
|
||||||
- P:及Partition Tolerance,通常情况下,节点之间的网络的断开被称之为network partition。故而,partition tolerance则是能够保证即使发生network partition,分布式系统中的节点也能够继续运行
|
- P:及Partition Tolerance,通常情况下,节点之间的网络的断开被称之为network partition。故而,partition tolerance则是能够保证即使发生network partition,分布式系统中的节点也能够继续运行
|
||||||
|
|
||||||
通常P是必选的,而在满足P的前提下,A和C只能够满足一条,即AP或CP。
|
通常P是必选的,而在满足P的前提下,A和C只能够满足一条,即AP或CP。
|
||||||
#### zookeeper遵循的原则
|
#### zookeeper遵循的原则
|
||||||
zookeeper遵循的是cp原则,如果zookeeper集群中的leader宕机,那么在新leader选举出来之前,zookeeper集群是拒绝向外提供服务的。
|
zookeeper遵循的是cp原则,如果zookeeper集群中的leader宕机,那么在新leader选举出来之前,zookeeper集群是拒绝向外提供服务的。
|
||||||
#### eureka遵循的原则
|
#### eureka遵循的原则
|
||||||
和zookeeper不同,eureka遵循的是ap原则,这这意味着eureka允许多个节点之间存在数据不一致的情况,即使某个节点的宕机,eureka仍然能够向外提供服务。
|
和zookeeper不同,eureka遵循的是ap原则,这这意味着eureka允许多个节点之间存在数据不一致的情况,即使某个节点的宕机,eureka仍然能够向外提供服务。
|
||||||
|
|
||||||
### eureka使用
|
### eureka使用
|
||||||
可以通过向项目中添加eureka-server的依赖来启动一个eureka-server实例。eureka-server作为注册中心,会将其本身也作为一个服务注册到注册中心中。
|
可以通过向项目中添加eureka-server的依赖来启动一个eureka-server实例。eureka-server作为注册中心,会将其本身也作为一个服务注册到注册中心中。
|
||||||
#### 注册实例id
|
#### 注册实例id
|
||||||
注册实例id由三部分组成,`主机名称:应用名称:端口号`构成了实例的id。每个实例id都唯一。
|
注册实例id由三部分组成,`主机名称:应用名称:端口号`构成了实例的id。每个实例id都唯一。
|
||||||
#### eureka-server配置
|
#### eureka-server配置
|
||||||
- eviction-interval-timer-in-ms:eureka-server会运行固定的scheduled task来清除过期的client,eviction-interval-timer-in-ms属性用于定义task之间的间隔,默认情况下该属性值为60s
|
- eviction-interval-timer-in-ms:eureka-server会运行固定的scheduled task来清除过期的client,eviction-interval-timer-in-ms属性用于定义task之间的间隔,默认情况下该属性值为60s
|
||||||
- renewal-percent-threshold:基于该属性,eureka来计算每分钟期望从所有客户端接受到的心跳数。根据eureka-server的自我保护机制,如果eureka-server收到的心跳数小于threshold,那么eureka-server会停止进行客户端实例的淘汰,直到接收到的心跳数大于threshold
|
- renewal-percent-threshold:基于该属性,eureka来计算每分钟期望从所有客户端接受到的心跳数。根据eureka-server的自我保护机制,如果eureka-server收到的心跳数小于threshold,那么eureka-server会停止进行客户端实例的淘汰,直到接收到的心跳数大于threshold
|
||||||
#### eureka-instance配置
|
#### eureka-instance配置
|
||||||
eureka-server-instance本身也作为一个instance注册到注册中心中,故而可以针对eureka-instance作一些配置。
|
eureka-server-instance本身也作为一个instance注册到注册中心中,故而可以针对eureka-instance作一些配置。
|
||||||
#### eureka集群
|
#### eureka集群
|
||||||
eureka集群是去中心化的集群,没有主机和从机的概念,eureka节点会向集群中所有其他的节点广播数据的变动。
|
eureka集群是去中心化的集群,没有主机和从机的概念,eureka节点会向集群中所有其他的节点广播数据的变动。
|
||||||
## Ribbon
|
## Ribbon
|
||||||
Spring Cloud Ribbon是一个基于Http和Tcp的客户端负载均衡工具,基于Netflix Ribbon实现,Ribbon主要用于提供负载均衡算法和服务调用。Ribbon的客户端组件提供了一套完善的配置项,如超时和重试等。
|
Spring Cloud Ribbon是一个基于Http和Tcp的客户端负载均衡工具,基于Netflix Ribbon实现,Ribbon主要用于提供负载均衡算法和服务调用。Ribbon的客户端组件提供了一套完善的配置项,如超时和重试等。
|
||||||
在通过Spring Cloud构建微服务时,Ribbon有两种使用方法,一种是和RedisTemplate结合使用,另一种是和OpenFegin相结合。
|
在通过Spring Cloud构建微服务时,Ribbon有两种使用方法,一种是和RedisTemplate结合使用,另一种是和OpenFegin相结合。
|
||||||
## OpenFeign
|
## OpenFeign
|
||||||
OpenFeign是一个远程调用组件,使用接口和注解以http的形式完成调用。
|
OpenFeign是一个远程调用组件,使用接口和注解以http的形式完成调用。
|
||||||
Feign中集成了Ribbon,而Ribbon中则集成了eureka。
|
Feign中集成了Ribbon,而Ribbon中则集成了eureka。
|
||||||
|
|||||||
@@ -1,234 +1,234 @@
|
|||||||
- [caffeine](#caffeine)
|
- [caffeine](#caffeine)
|
||||||
- [Cache](#cache)
|
- [Cache](#cache)
|
||||||
- [注入](#注入)
|
- [注入](#注入)
|
||||||
- [手动](#手动)
|
- [手动](#手动)
|
||||||
- [Loading](#loading)
|
- [Loading](#loading)
|
||||||
- [异步(手动)](#异步手动)
|
- [异步(手动)](#异步手动)
|
||||||
- [Async Loading](#async-loading)
|
- [Async Loading](#async-loading)
|
||||||
- [淘汰](#淘汰)
|
- [淘汰](#淘汰)
|
||||||
- [基于时间的](#基于时间的)
|
- [基于时间的](#基于时间的)
|
||||||
- [基于时间的淘汰策略](#基于时间的淘汰策略)
|
- [基于时间的淘汰策略](#基于时间的淘汰策略)
|
||||||
- [基于引用的淘汰策略](#基于引用的淘汰策略)
|
- [基于引用的淘汰策略](#基于引用的淘汰策略)
|
||||||
- [移除](#移除)
|
- [移除](#移除)
|
||||||
- [removal listener](#removal-listener)
|
- [removal listener](#removal-listener)
|
||||||
- [compute](#compute)
|
- [compute](#compute)
|
||||||
- [统计](#统计)
|
- [统计](#统计)
|
||||||
- [cleanup](#cleanup)
|
- [cleanup](#cleanup)
|
||||||
- [软引用和弱引用](#软引用和弱引用)
|
- [软引用和弱引用](#软引用和弱引用)
|
||||||
- [weakKeys](#weakkeys)
|
- [weakKeys](#weakkeys)
|
||||||
- [weakValues](#weakvalues)
|
- [weakValues](#weakvalues)
|
||||||
- [softValues](#softvalues)
|
- [softValues](#softvalues)
|
||||||
|
|
||||||
|
|
||||||
# caffeine
|
# caffeine
|
||||||
caffeine是一个高性能的java缓存库,其几乎能够提供最佳的命中率。
|
caffeine是一个高性能的java缓存库,其几乎能够提供最佳的命中率。
|
||||||
cache类似于ConcurrentMap,但并不完全相同。在ConcurrentMap中,会维护所有添加到其中的元素,直到元素被显式移除;而Cache则是可以通过配置来自动的淘汰元素,从而限制cache的内存占用。
|
cache类似于ConcurrentMap,但并不完全相同。在ConcurrentMap中,会维护所有添加到其中的元素,直到元素被显式移除;而Cache则是可以通过配置来自动的淘汰元素,从而限制cache的内存占用。
|
||||||
## Cache
|
## Cache
|
||||||
### 注入
|
### 注入
|
||||||
Cache提供了如下的注入策略
|
Cache提供了如下的注入策略
|
||||||
#### 手动
|
#### 手动
|
||||||
```java
|
```java
|
||||||
Cache<Key, Graph> cache = Caffeine.newBuilder()
|
Cache<Key, Graph> cache = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(10, TimeUnit.MINUTES)
|
.expireAfterWrite(10, TimeUnit.MINUTES)
|
||||||
.maximumSize(10_000)
|
.maximumSize(10_000)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Lookup an entry, or null if not found
|
// Lookup an entry, or null if not found
|
||||||
Graph graph = cache.getIfPresent(key);
|
Graph graph = cache.getIfPresent(key);
|
||||||
// Lookup and compute an entry if absent, or null if not computable
|
// Lookup and compute an entry if absent, or null if not computable
|
||||||
graph = cache.get(key, k -> createExpensiveGraph(key));
|
graph = cache.get(key, k -> createExpensiveGraph(key));
|
||||||
// Insert or update an entry
|
// Insert or update an entry
|
||||||
cache.put(key, graph);
|
cache.put(key, graph);
|
||||||
// Remove an entry
|
// Remove an entry
|
||||||
cache.invalidate(key);
|
cache.invalidate(key);
|
||||||
```
|
```
|
||||||
Cache接口可以显示的操作缓存条目的获取、失效、更新。
|
Cache接口可以显示的操作缓存条目的获取、失效、更新。
|
||||||
条目可以直接通过cache.put(key,value)来插入到缓存中,该操作会覆盖已存在的key对应的条目。
|
条目可以直接通过cache.put(key,value)来插入到缓存中,该操作会覆盖已存在的key对应的条目。
|
||||||
也可以使用cache.get(key,k->value)的形式来对缓存进行插入,该方法会在缓存中查找key对应的条目,如果不存在,会调用k->value来进行计算并将计算后的将计算后的结果插入到缓存中。该操作是原子的。如果该条目不可计算,会返回null,如果计算过程中发生异常,则是会抛出异常。
|
也可以使用cache.get(key,k->value)的形式来对缓存进行插入,该方法会在缓存中查找key对应的条目,如果不存在,会调用k->value来进行计算并将计算后的将计算后的结果插入到缓存中。该操作是原子的。如果该条目不可计算,会返回null,如果计算过程中发生异常,则是会抛出异常。
|
||||||
除上述方法外,也可以通过cache.asMap()返回map对象,并且调用ConcurrentMap中的接口来对缓存条目进行修改。
|
除上述方法外,也可以通过cache.asMap()返回map对象,并且调用ConcurrentMap中的接口来对缓存条目进行修改。
|
||||||
#### Loading
|
#### Loading
|
||||||
```java
|
```java
|
||||||
// build方法可以指定一个CacheLoader参数
|
// build方法可以指定一个CacheLoader参数
|
||||||
LoadingCache<Key, Graph> cache = Caffeine.newBuilder()
|
LoadingCache<Key, Graph> cache = Caffeine.newBuilder()
|
||||||
.maximumSize(10_000)
|
.maximumSize(10_000)
|
||||||
.expireAfterWrite(10, TimeUnit.MINUTES)
|
.expireAfterWrite(10, TimeUnit.MINUTES)
|
||||||
.build(key -> createExpensiveGraph(key));
|
.build(key -> createExpensiveGraph(key));
|
||||||
|
|
||||||
// Lookup and compute an entry if absent, or null if not computable
|
// Lookup and compute an entry if absent, or null if not computable
|
||||||
Graph graph = cache.get(key);
|
Graph graph = cache.get(key);
|
||||||
// Lookup and compute entries that are absent
|
// Lookup and compute entries that are absent
|
||||||
Map<Key, Graph> graphs = cache.getAll(keys);
|
Map<Key, Graph> graphs = cache.getAll(keys);
|
||||||
```
|
```
|
||||||
LoadingCache和CacheLoader相关联。
|
LoadingCache和CacheLoader相关联。
|
||||||
可以通过getAll方法来执行批量查找,默认情况下,getAll方法会为每个cache中不存在的key向CacheLoader.load发送一个请求。当批量查找比许多单独的查找效率更加高时,可以重写CacheLoader.loadAll方法。
|
可以通过getAll方法来执行批量查找,默认情况下,getAll方法会为每个cache中不存在的key向CacheLoader.load发送一个请求。当批量查找比许多单独的查找效率更加高时,可以重写CacheLoader.loadAll方法。
|
||||||
#### 异步(手动)
|
#### 异步(手动)
|
||||||
```java
|
```java
|
||||||
AsyncCache<Key, Graph> cache = Caffeine.newBuilder()
|
AsyncCache<Key, Graph> cache = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(10, TimeUnit.MINUTES)
|
.expireAfterWrite(10, TimeUnit.MINUTES)
|
||||||
.maximumSize(10_000)
|
.maximumSize(10_000)
|
||||||
.buildAsync();
|
.buildAsync();
|
||||||
|
|
||||||
// Lookup an entry, or null if not found
|
// Lookup an entry, or null if not found
|
||||||
CompletableFuture<Graph> graph = cache.getIfPresent(key);
|
CompletableFuture<Graph> graph = cache.getIfPresent(key);
|
||||||
// Lookup and asynchronously compute an entry if absent
|
// Lookup and asynchronously compute an entry if absent
|
||||||
graph = cache.get(key, k -> createExpensiveGraph(key));
|
graph = cache.get(key, k -> createExpensiveGraph(key));
|
||||||
// Insert or update an entry
|
// Insert or update an entry
|
||||||
cache.put(key, graph);
|
cache.put(key, graph);
|
||||||
// Remove an entry
|
// Remove an entry
|
||||||
cache.synchronous().invalidate(key);
|
cache.synchronous().invalidate(key);
|
||||||
```
|
```
|
||||||
AsyncCache允许异步的计算条目,并且返回CompletableFuture。
|
AsyncCache允许异步的计算条目,并且返回CompletableFuture。
|
||||||
AsyncCache可以调用synchronous方法来提供同步的视图。
|
AsyncCache可以调用synchronous方法来提供同步的视图。
|
||||||
默认情况下executor是ForkJoinPool.commonPool(),可以通过Caffeine.executor(threadPool)来进行覆盖。
|
默认情况下executor是ForkJoinPool.commonPool(),可以通过Caffeine.executor(threadPool)来进行覆盖。
|
||||||
#### Async Loading
|
#### Async Loading
|
||||||
```java
|
```java
|
||||||
AsyncLoadingCache<Key, Graph> cache = Caffeine.newBuilder()
|
AsyncLoadingCache<Key, Graph> cache = Caffeine.newBuilder()
|
||||||
.maximumSize(10_000)
|
.maximumSize(10_000)
|
||||||
.expireAfterWrite(10, TimeUnit.MINUTES)
|
.expireAfterWrite(10, TimeUnit.MINUTES)
|
||||||
// Either: Build with a synchronous computation that is wrapped as asynchronous
|
// Either: Build with a synchronous computation that is wrapped as asynchronous
|
||||||
.buildAsync(key -> createExpensiveGraph(key));
|
.buildAsync(key -> createExpensiveGraph(key));
|
||||||
// Or: Build with a asynchronous computation that returns a future
|
// Or: Build with a asynchronous computation that returns a future
|
||||||
.buildAsync((key, executor) -> createExpensiveGraphAsync(key, executor));
|
.buildAsync((key, executor) -> createExpensiveGraphAsync(key, executor));
|
||||||
|
|
||||||
// Lookup and asynchronously compute an entry if absent
|
// Lookup and asynchronously compute an entry if absent
|
||||||
CompletableFuture<Graph> graph = cache.get(key);
|
CompletableFuture<Graph> graph = cache.get(key);
|
||||||
// Lookup and asynchronously compute entries that are absent
|
// Lookup and asynchronously compute entries that are absent
|
||||||
CompletableFuture<Map<Key, Graph>> graphs = cache.getAll(keys);
|
CompletableFuture<Map<Key, Graph>> graphs = cache.getAll(keys);
|
||||||
```
|
```
|
||||||
AsyncLoadingCache是一个AsyncCache加上一个AsyncCacheLoader。
|
AsyncLoadingCache是一个AsyncCache加上一个AsyncCacheLoader。
|
||||||
同样地,AsyncCacheLoader支持重写load和loadAll方法。
|
同样地,AsyncCacheLoader支持重写load和loadAll方法。
|
||||||
### 淘汰
|
### 淘汰
|
||||||
Caffeine提供了三种类型的淘汰:基于size的,基于时间的,基于引用的。
|
Caffeine提供了三种类型的淘汰:基于size的,基于时间的,基于引用的。
|
||||||
#### 基于时间的
|
#### 基于时间的
|
||||||
```java
|
```java
|
||||||
// Evict based on the number of entries in the cache
|
// Evict based on the number of entries in the cache
|
||||||
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
||||||
.maximumSize(10_000)
|
.maximumSize(10_000)
|
||||||
.build(key -> createExpensiveGraph(key));
|
.build(key -> createExpensiveGraph(key));
|
||||||
|
|
||||||
// Evict based on the number of vertices in the cache
|
// Evict based on the number of vertices in the cache
|
||||||
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
||||||
.maximumWeight(10_000)
|
.maximumWeight(10_000)
|
||||||
.weigher((Key key, Graph graph) -> graph.vertices().size())
|
.weigher((Key key, Graph graph) -> graph.vertices().size())
|
||||||
.build(key -> createExpensiveGraph(key));
|
.build(key -> createExpensiveGraph(key));
|
||||||
```
|
```
|
||||||
如果你的缓存不应该超过特定的容量限制,应该使用`Caffeine.maximumSize(long)`方法。该缓存会对不常用的条目进行淘汰。
|
如果你的缓存不应该超过特定的容量限制,应该使用`Caffeine.maximumSize(long)`方法。该缓存会对不常用的条目进行淘汰。
|
||||||
如果每条记录的权重不同,那么可以通过`Caffeine.weigher(Weigher)`指定一个权重计算方法,并且通过`Caffeine.maximumWeight(long)`指定缓存最大的权重值。
|
如果每条记录的权重不同,那么可以通过`Caffeine.weigher(Weigher)`指定一个权重计算方法,并且通过`Caffeine.maximumWeight(long)`指定缓存最大的权重值。
|
||||||
#### 基于时间的淘汰策略
|
#### 基于时间的淘汰策略
|
||||||
```java
|
```java
|
||||||
// Evict based on a fixed expiration policy
|
// Evict based on a fixed expiration policy
|
||||||
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
||||||
.expireAfterAccess(5, TimeUnit.MINUTES)
|
.expireAfterAccess(5, TimeUnit.MINUTES)
|
||||||
.build(key -> createExpensiveGraph(key));
|
.build(key -> createExpensiveGraph(key));
|
||||||
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(10, TimeUnit.MINUTES)
|
.expireAfterWrite(10, TimeUnit.MINUTES)
|
||||||
.build(key -> createExpensiveGraph(key));
|
.build(key -> createExpensiveGraph(key));
|
||||||
|
|
||||||
// Evict based on a varying expiration policy
|
// Evict based on a varying expiration policy
|
||||||
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
||||||
.expireAfter(new Expiry<Key, Graph>() {
|
.expireAfter(new Expiry<Key, Graph>() {
|
||||||
public long expireAfterCreate(Key key, Graph graph, long currentTime) {
|
public long expireAfterCreate(Key key, Graph graph, long currentTime) {
|
||||||
// Use wall clock time, rather than nanotime, if from an external resource
|
// Use wall clock time, rather than nanotime, if from an external resource
|
||||||
long seconds = graph.creationDate().plusHours(5)
|
long seconds = graph.creationDate().plusHours(5)
|
||||||
.minus(System.currentTimeMillis(), MILLIS)
|
.minus(System.currentTimeMillis(), MILLIS)
|
||||||
.toEpochSecond();
|
.toEpochSecond();
|
||||||
return TimeUnit.SECONDS.toNanos(seconds);
|
return TimeUnit.SECONDS.toNanos(seconds);
|
||||||
}
|
}
|
||||||
public long expireAfterUpdate(Key key, Graph graph,
|
public long expireAfterUpdate(Key key, Graph graph,
|
||||||
long currentTime, long currentDuration) {
|
long currentTime, long currentDuration) {
|
||||||
return currentDuration;
|
return currentDuration;
|
||||||
}
|
}
|
||||||
public long expireAfterRead(Key key, Graph graph,
|
public long expireAfterRead(Key key, Graph graph,
|
||||||
long currentTime, long currentDuration) {
|
long currentTime, long currentDuration) {
|
||||||
return currentDuration;
|
return currentDuration;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.build(key -> createExpensiveGraph(key));
|
.build(key -> createExpensiveGraph(key));
|
||||||
```
|
```
|
||||||
caffine提供三种方法来进行基于时间的淘汰:
|
caffine提供三种方法来进行基于时间的淘汰:
|
||||||
- expireAfterAccess(long, TimeUnit):基于上次读写操作过后的时间来进行淘汰
|
- expireAfterAccess(long, TimeUnit):基于上次读写操作过后的时间来进行淘汰
|
||||||
- expireAfterWrite(long, TimeUnit):基于创建时间、或上次写操作执行的时间来进行淘汰
|
- expireAfterWrite(long, TimeUnit):基于创建时间、或上次写操作执行的时间来进行淘汰
|
||||||
- expireAfter(Expire):基于自定义的策略来进行淘汰
|
- expireAfter(Expire):基于自定义的策略来进行淘汰
|
||||||
过期在写操作之间周期性的进行触发,偶尔也会在读操作之间进行出发。调度和发送过期事件都是在o(1)时间之内完成的。
|
过期在写操作之间周期性的进行触发,偶尔也会在读操作之间进行出发。调度和发送过期事件都是在o(1)时间之内完成的。
|
||||||
为了及时过期,而不是通过缓存活动来触发过期,可以通过`Caffeine.scheuler(scheduler)`来指定调度线程
|
为了及时过期,而不是通过缓存活动来触发过期,可以通过`Caffeine.scheuler(scheduler)`来指定调度线程
|
||||||
#### 基于引用的淘汰策略
|
#### 基于引用的淘汰策略
|
||||||
```java
|
```java
|
||||||
// Evict when neither the key nor value are strongly reachable
|
// Evict when neither the key nor value are strongly reachable
|
||||||
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
||||||
.weakKeys()
|
.weakKeys()
|
||||||
.weakValues()
|
.weakValues()
|
||||||
.build(key -> createExpensiveGraph(key));
|
.build(key -> createExpensiveGraph(key));
|
||||||
|
|
||||||
// Evict when the garbage collector needs to free memory
|
// Evict when the garbage collector needs to free memory
|
||||||
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
||||||
.softValues()
|
.softValues()
|
||||||
.build(key -> createExpensiveGraph(key));
|
.build(key -> createExpensiveGraph(key));
|
||||||
```
|
```
|
||||||
caffeine允许设置cache支持垃圾回收,通过使用为key指定weak reference,为value制定soft reference
|
caffeine允许设置cache支持垃圾回收,通过使用为key指定weak reference,为value制定soft reference
|
||||||
|
|
||||||
### 移除
|
### 移除
|
||||||
可以通过下述方法显式移除条目:
|
可以通过下述方法显式移除条目:
|
||||||
```java
|
```java
|
||||||
// individual key
|
// individual key
|
||||||
cache.invalidate(key)
|
cache.invalidate(key)
|
||||||
// bulk keys
|
// bulk keys
|
||||||
cache.invalidateAll(keys)
|
cache.invalidateAll(keys)
|
||||||
// all keys
|
// all keys
|
||||||
cache.invalidateAll()
|
cache.invalidateAll()
|
||||||
```
|
```
|
||||||
#### removal listener
|
#### removal listener
|
||||||
```java
|
```java
|
||||||
Cache<Key, Graph> graphs = Caffeine.newBuilder()
|
Cache<Key, Graph> graphs = Caffeine.newBuilder()
|
||||||
.evictionListener((Key key, Graph graph, RemovalCause cause) ->
|
.evictionListener((Key key, Graph graph, RemovalCause cause) ->
|
||||||
System.out.printf("Key %s was evicted (%s)%n", key, cause))
|
System.out.printf("Key %s was evicted (%s)%n", key, cause))
|
||||||
.removalListener((Key key, Graph graph, RemovalCause cause) ->
|
.removalListener((Key key, Graph graph, RemovalCause cause) ->
|
||||||
System.out.printf("Key %s was removed (%s)%n", key, cause))
|
System.out.printf("Key %s was removed (%s)%n", key, cause))
|
||||||
.build();
|
.build();
|
||||||
```
|
```
|
||||||
在entry被移除时,可以指定listener来执行一系列操作,通过`Caffeine.removalListener(RemovalListener)`。操作是通过Executor异步执行的。
|
在entry被移除时,可以指定listener来执行一系列操作,通过`Caffeine.removalListener(RemovalListener)`。操作是通过Executor异步执行的。
|
||||||
当想要在缓存失效之后同步执行操作时,可以使用`Caffeine.evictionListener(RemovalListener)`.该监听器将会在`RemovalCause.wasEvicted()`时被触发
|
当想要在缓存失效之后同步执行操作时,可以使用`Caffeine.evictionListener(RemovalListener)`.该监听器将会在`RemovalCause.wasEvicted()`时被触发
|
||||||
### compute
|
### compute
|
||||||
通过compute,caffeine可以在entry创建、淘汰、更新时,原子的执行一系列操作:
|
通过compute,caffeine可以在entry创建、淘汰、更新时,原子的执行一系列操作:
|
||||||
```java
|
```java
|
||||||
Cache<Key, Graph> graphs = Caffeine.newBuilder()
|
Cache<Key, Graph> graphs = Caffeine.newBuilder()
|
||||||
.evictionListener((Key key, Graph graph, RemovalCause cause) -> {
|
.evictionListener((Key key, Graph graph, RemovalCause cause) -> {
|
||||||
// atomically intercept the entry's eviction
|
// atomically intercept the entry's eviction
|
||||||
}).build();
|
}).build();
|
||||||
|
|
||||||
graphs.asMap().compute(key, (k, v) -> {
|
graphs.asMap().compute(key, (k, v) -> {
|
||||||
Graph graph = createExpensiveGraph(key);
|
Graph graph = createExpensiveGraph(key);
|
||||||
... // update a secondary store
|
... // update a secondary store
|
||||||
return graph;
|
return graph;
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
### 统计
|
### 统计
|
||||||
通过`Caffeine.recordStats()`方法,可以启用统计信息的收集,`cache.stats()`方法将返回一个CacheStats对象,提供如下接口:
|
通过`Caffeine.recordStats()`方法,可以启用统计信息的收集,`cache.stats()`方法将返回一个CacheStats对象,提供如下接口:
|
||||||
- hitRate():返回请求命中率
|
- hitRate():返回请求命中率
|
||||||
- evictionCount():cache淘汰次数
|
- evictionCount():cache淘汰次数
|
||||||
- averageLoadPenalty():load新值花费的平均时间
|
- averageLoadPenalty():load新值花费的平均时间
|
||||||
```java
|
```java
|
||||||
Cache<Key, Graph> graphs = Caffeine.newBuilder()
|
Cache<Key, Graph> graphs = Caffeine.newBuilder()
|
||||||
.maximumSize(10_000)
|
.maximumSize(10_000)
|
||||||
.recordStats()
|
.recordStats()
|
||||||
.build();
|
.build();
|
||||||
```
|
```
|
||||||
### cleanup
|
### cleanup
|
||||||
默认情况下,Caffine并不会在自动淘汰entry后或entry失效之后立即进行清理,而是在写操作之后执行少量的清理工作,如果写操作很少,则是偶尔在读操作后执行少量读操作。
|
默认情况下,Caffine并不会在自动淘汰entry后或entry失效之后立即进行清理,而是在写操作之后执行少量的清理工作,如果写操作很少,则是偶尔在读操作后执行少量读操作。
|
||||||
如果你的缓存是高吞吐量的,那么不必担心过期缓存的清理,如果你的缓存读写操作都比较少,那么需要新建一个外部线程来调用`Cache.cleanUp()`来进行缓存清理。
|
如果你的缓存是高吞吐量的,那么不必担心过期缓存的清理,如果你的缓存读写操作都比较少,那么需要新建一个外部线程来调用`Cache.cleanUp()`来进行缓存清理。
|
||||||
```java
|
```java
|
||||||
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
|
||||||
.scheduler(Scheduler.systemScheduler())
|
.scheduler(Scheduler.systemScheduler())
|
||||||
.expireAfterWrite(10, TimeUnit.MINUTES)
|
.expireAfterWrite(10, TimeUnit.MINUTES)
|
||||||
.build(key -> createExpensiveGraph(key));
|
.build(key -> createExpensiveGraph(key));
|
||||||
```
|
```
|
||||||
scheduler可以用于及时的清理过期缓存
|
scheduler可以用于及时的清理过期缓存
|
||||||
|
|
||||||
### 软引用和弱引用
|
### 软引用和弱引用
|
||||||
caffeine支持基于引用来设置淘汰策略。caffeine支持针对key和value使用弱引用,针对value使用软引用。
|
caffeine支持基于引用来设置淘汰策略。caffeine支持针对key和value使用弱引用,针对value使用软引用。
|
||||||
#### weakKeys
|
#### weakKeys
|
||||||
`caffeine.weakKeys()`存储使用弱引用的key,如果没有强引用指向key,那么key将会被垃圾回收。垃圾回收时只会比较对象地址,故而整个缓存在比较key时会通过`==`而不是`equals`来进行比较
|
`caffeine.weakKeys()`存储使用弱引用的key,如果没有强引用指向key,那么key将会被垃圾回收。垃圾回收时只会比较对象地址,故而整个缓存在比较key时会通过`==`而不是`equals`来进行比较
|
||||||
#### weakValues
|
#### weakValues
|
||||||
`caffeine.weakValues()`存储使用弱引用的value,如果没有强引用指向value,value会被垃圾回收。同样地,在整个cache中,会使用`==`而不是`equals`来对value进行比较
|
`caffeine.weakValues()`存储使用弱引用的value,如果没有强引用指向value,value会被垃圾回收。同样地,在整个cache中,会使用`==`而不是`equals`来对value进行比较
|
||||||
#### softValues
|
#### softValues
|
||||||
软引用的value通常会在垃圾回收时按照lru的方式进行回收,根据内存情况决定是否进行回收。由于使用软引用会带来性能问题,通常更推荐使用基于max-size的回收策略。
|
软引用的value通常会在垃圾回收时按照lru的方式进行回收,根据内存情况决定是否进行回收。由于使用软引用会带来性能问题,通常更推荐使用基于max-size的回收策略。
|
||||||
同样地,基于软引用的value在整个缓存中会通过`==`而不是`equals()`来进行垃圾回收。
|
同样地,基于软引用的value在整个缓存中会通过`==`而不是`equals()`来进行垃圾回收。
|
||||||
|
|||||||
83
中间件/redis/redis sentinel.md
Normal file
83
中间件/redis/redis sentinel.md
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
- [redis sentinel](#redis-sentinel)
|
||||||
|
- [sentinel as a distributed system](#sentinel-as-a-distributed-system)
|
||||||
|
- [sentinel部署要点](#sentinel部署要点)
|
||||||
|
- [sentinel配置](#sentinel配置)
|
||||||
|
- [sentinel monitor](#sentinel-monitor)
|
||||||
|
- [其他sentinel选项](#其他sentinel选项)
|
||||||
|
- [down-after-milliseconds](#down-after-milliseconds)
|
||||||
|
- [parallel-syncs](#parallel-syncs)
|
||||||
|
|
||||||
|
|
||||||
|
# redis sentinel
|
||||||
|
## sentinel as a distributed system
|
||||||
|
redis sentinel是一个分布式系统,其设计旨在多个sentinel进程协同工作。
|
||||||
|
|
||||||
|
redis sentinel的优势如下:
|
||||||
|
- 当多个sentinel节点都一致认为master不再可访问时,将会触发故障检测机制。该机制能够有效的降低false positive几率
|
||||||
|
- 即使并非所有sentinel进程都正常工作,sentinel机制仍然能够正常工作,确保整个sentinel机制拥有容错性
|
||||||
|
|
||||||
|
sentinels、redis实例、客户端共同构成了包含特定属性的更大分布式系统。
|
||||||
|
|
||||||
|
sentinels默认会监听26379端口, sentinels实例之间会通过该端口进行通信。如果该端口未开放,那么sentinels之间将无法通信,也无法协商一致,failover将不会被执行。
|
||||||
|
|
||||||
|
### sentinel部署要点
|
||||||
|
- 对于一个具备鲁棒性的形同部署而言,至少需要三个sentinels进程实例
|
||||||
|
- 三个sentinel实例应当被部署在独立故障的计算机/虚拟机中
|
||||||
|
- sentinel + redis 分布式系统并不保证在发生故障时,对系统的`acked writes`不被丢失。
|
||||||
|
- 因为redis的replication是异步的,故而在发生故障时可能会丢失部分写入
|
||||||
|
- clients需要sentinel支持,大部分client library中包含sentinel支持
|
||||||
|
|
||||||
|
### sentinel配置
|
||||||
|
redis包含一个名为`sentinel.conf`的文件,用于配置sentinel,典型的最小化配置如下:
|
||||||
|
```redis
|
||||||
|
sentinel monitor mymaster 127.0.0.1 6379 2
|
||||||
|
sentinel down-after-milliseconds mymaster 60000
|
||||||
|
sentinel failover-timeout mymaster 180000
|
||||||
|
sentinel parallel-syncs mymaster 1
|
||||||
|
|
||||||
|
sentinel monitor resque 192.168.1.3 6380 4
|
||||||
|
sentinel down-after-milliseconds resque 10000
|
||||||
|
sentinel failover-timeout resque 180000
|
||||||
|
sentinel parallel-syncs resque 5
|
||||||
|
```
|
||||||
|
|
||||||
|
只需要指定监控的主节点,并为每个主节点指定不同的名称。无需手动指定replicas,系统会自动发现replicas。sentinel将会自动使用replicas的额外信息来更新配置。
|
||||||
|
|
||||||
|
并且,发生故障转移replica被提升为主节点时/新sentinel被发现时,该配置文件也会被重写。
|
||||||
|
|
||||||
|
在上述配置文件示例中,监控了两个redis实例集合,每个redis实例集合都由一个master和一系列replicas组成。上述,一个集合被称为`mymaster`,另一个集合被称为`resque`。
|
||||||
|
|
||||||
|
### sentinel monitor
|
||||||
|
```
|
||||||
|
sentinel monitor <master-name> <ip> <port> <quorum>
|
||||||
|
```
|
||||||
|
上述是`sentinel monitor`的语法,其用于告知redis监控名为`mymaster`的master实例,并且其地址为`127.0.0.1`,端口号为`6379`,quorum为2。
|
||||||
|
|
||||||
|
其中,quorum的含义如下:
|
||||||
|
- quorm为需要达成`master不可访问`这一共识的sentinels数量,其将将master标记为失败,并且在条件允许的情况下启动failover
|
||||||
|
- quorum仅用于检测失败。为了实际的执行故障转移,sentinels中的一个需要被选举为leader,这需要获取多数sentinel进程的投票后才能完成
|
||||||
|
|
||||||
|
例如,假设有5个sentinel进程,并且给定master的quorum为2,那么:
|
||||||
|
- 如果两个sentinels达成共识master不可访问,那么其中一个sentinel将会尝试开启故障转移
|
||||||
|
- 只有当至少存在3个sentinels可访问时,故障转移才会被授权,并实际启动故障转移
|
||||||
|
|
||||||
|
在实际应用中,少数派分区将永远不会在故障时触发故障转移。
|
||||||
|
|
||||||
|
### 其他sentinel选项
|
||||||
|
其他sentinel选项的格式集合都如下:
|
||||||
|
```
|
||||||
|
sentinel <option_name> <master_name> <option_value>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### down-after-milliseconds
|
||||||
|
`down-after-milliseconds`选项代表sentinel认为实例宕机的时间,在该段时间内实例应当是不可访问的
|
||||||
|
|
||||||
|
#### parallel-syncs
|
||||||
|
`parallel-syncs`代表故障转移时,replicas同时被重新配置的数量。replicas在故障转移时,会被重新配置并使用新的master节点。
|
||||||
|
|
||||||
|
- 当`parallel-syncs`参数指定的值被降低时,故障转移过程耗费的时间将会增加
|
||||||
|
- replication过程通常是非阻塞的,但是其间有一个时间段会中止并从master批量加载数据。此时,可能并不希望所有的replicas都不可用并从新master同步数据
|
||||||
|
|
||||||
|
配置参数可以在运行时被修改,
|
||||||
|
- 针对master的配置参数可以通过`SENTINEL SET`命令修改
|
||||||
|
- 全局配置参数可以通过`SENTINEL CONFIG SET`命令来进行修改
|
||||||
Reference in New Issue
Block a user