天天看點

SQL Server AlwaysON 同步模式的疑似陷阱

SQL Server 2012 推出的最重要的功能之一Alwayson,是一個集之前Cluster和Mirror于一體的新功能,即解決了Cluster依賴共享存儲的問題,又解決了鏡像不能實時讀以及轉移後連接配接串需要添加轉移IP的問題,看起來的确很實用。

而且Alwayson多副本的功能為實作讀寫分離提供了可能,試想一下,當主副本壓力比較大的時候,是否可以将讀操作引向輔助副本呢?答案一般來講是肯定的,請注意,是一般!

遺憾的是,這個同步并不是資料的實時同步,當主副本資料發生變化時,同步模式下的輔助副本并不能立即取到變化的資料。

實驗如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

<code>EXEC</code> <code>sp_addlinkedserver @server = N</code><code>'Secondary'</code><code>, @srvproduct = N</code><code>''</code><code>,</code>

<code>    </code><code>@provider = N</code><code>'SQLNCLI'</code><code>, @datasrc = N</code><code>'192.168.200.201'</code><code>;</code>

<code>EXEC</code> <code>sp_addlinkedsrvlogin</code><code>'Secondary '</code><code>,</code><code>'false '</code><code>,</code><code>NULL</code><code>,</code><code>'sa'</code><code>,</code><code>'sqlcn.com'</code>

<code>USE DemoDB</code>

<code>go</code>

<code>CREATE</code> <code>TABLE</code> <code>tb_alwayson</code>

<code>    </code><code>(</code>

<code>      </code><code>id</code><code>INT</code> <code>IDENTITY</code>

<code>             </code><code>PRIMARY</code> <code>KEY</code> <code>,</code>

<code>      </code><code>name</code> <code>VARCHAR</code><code>(200)</code>

<code>    </code><code>)</code>

<code>INSERT</code>  <code>INTO</code> <code>tb_alwayson</code>

<code>        </code><code>(</code><code>name</code> <code>)</code>

<code>        </code><code>SELECT</code>  <code>NEWID()</code>

<code>SELECT</code>  <code>COUNT</code><code>(*)</code>

<code>FROM</code>    <code>tb_alwayson</code>

<code>WAITFOR DELAY</code><code>'00:00:00.900'</code>

<code>FROM</code>    <code>Secondary.DemoDB.dbo.tb_alwayson</code>

使用連接配接伺服器,這是一個非常好了解的測試辦法,在我的環境裡,你會發現,在輔助副本上要取到變化的資料,大概要900ms才能保證,900ms以下,都沒法保證,甚至在300ms以下,沒出現過一次能同步的情況。

這就是同步模式,讓你沒有一點點兒防備。

<a href="http://www.sqlcn.com/wp-content/uploads/2014/05/image5.png"></a>

那麼這個同步模式到底是怎麼個同步呢?

答案是這樣的:它可以保證事務日志是同步的,也就是可以保證不丢失資料,但不能保證資料變化沒有延時,這是由于輔助副本在接收主副本傳來的Trans log時,首先将其緩到本地Log Cache,接着強制硬化到本地Ldf,然後随即向主副本告知你可以commit了,但注意,此時的硬化到本地ldf并非本地資料已經變化,這是因為輔助副本将trans log硬化到本地的同時,它是使用一個異步程序去redo這些trans log産生的Page變化到Data檔案的,這也就決定了這個Redo的操作是不可能比硬化日志早的,是以資料的延時就是肯定的了。

《SQL Server 2012實施與管理實戰指南》中指AlwaysON同步過程如下:

任何一個SQL Server裡都有個叫Log Writer的線程,當任何一個SQL使用者送出一個資料修改事務時,

它會負責把記錄本次修改的日志資訊先記入一段記憶體中的日志緩沖區,然後再寫入實體日志檔案(日志固化)。

是以對于任何一個資料庫,日志檔案裡都會有所有資料變化的記錄。

對于配置為AlwaysOn主副本的資料庫,SQL Server會為它建立一個叫Log Scanner的工作線程。

這個線程專門負責将日志記錄從日志緩沖區或者日志檔案裡中讀出,打包成日志塊,發送給各個輔助副本。

由于它的不間斷工作,才使主副本上的資料變化,可以不斷地向輔助副本上傳播。

在輔助副本上,同樣會有兩個線程,完成相應的資料更新動作,它們是固化(Harden)和重做(Redo)。

固化線程會将主副本Log Scanner所發過來的日志塊寫入輔助副本的磁盤上的日志檔案裡(這個過程被稱為"固化")。

而重做線程,則負責從磁盤上讀取日志塊,将日志記錄翻譯成資料修改操作,在輔助副本的資料庫上完成。

當重做線程完成其工作以後,輔助副本上的資料庫就會跟主副本一緻了。AlwaysOn就是通過這種機制,保持副本之間的同步。

重做線程每隔固定的時間點,會跟主副本通信,告知它自己的工作進度。主副本就能夠知道兩邊資料的差距有多遠。

這些線程在工作上各自獨立,以達到更高的效率。Log Scanner負責傳送日志塊,而無須等待Log Writer完成日志固化;輔助副本完成日志固化以後就會發送消息到主副本,告知資料已經傳遞完畢,而無須等待重做完成。其設計目标,是盡可能地減少AlwaysOn所帶來的額外操作對正常資料庫操作的性能影響。

<a href="http://www.sqlcn.com/wp-content/uploads/2014/05/image6.png"></a>

事實已經很清楚了,同步的原理決定了資料的延時,想用AlwaysON做讀寫分離的朋友們,考慮好你所能容忍的延時時間吧!

另外,微軟你敢在官方聯機文檔與各種技術大會上把同步模式非資料實時同步提一下嗎?