『壹』 緩存使用,前台直接操作mysql,後台操作緩存.怎麼保證數據一致性
特別要注意:不要設置環境變數CATALINA_HOME 2.分別修改安裝目錄下的conf子目錄中的server.xml文件: a.修改http訪問埠(默認為8080埠),將8080修改為tomcat不在使用的埠號。此處所設的埠號即是以後訪問web時所用的埠號。
『貳』 怎麼避免mysql從庫同步 怎麼保證數據一致性
用 pt-table-checksum 時,會不會影響業務性能?
實驗
實驗開始前,給大家分享一個小經驗:任何性能評估,不要相信別人的評測結果,要在自己的環境上測試,並(大概)知曉原理。
我們先建一對主從:
之後工具獲取了一個數據塊的 checksum,這個數據塊不大,如果跟業務流量有沖突,會馬上出發 innodb 的鎖超時,立刻退讓。
以上是 pt-table-checksum 的一些設計,可以看到這幾處都是精心維護了業務流量不受影響。
工具還設計了其他的一些機制保障業務流量,比如參數 --max-load 和 --pause-file 等,還有精心設計的數據塊劃分方法,索引選擇方法等。大家根據自己的情況配合使用即可達到很好的效果。
總結
本期我們介紹了簡單分析 pt-table-checksum 是否會影響業務流量,坊間會流傳工具的各種參數建議或者不建議使用,算命的情況比較多,大家都可以用簡單的實驗來分析其中機制。
還是那個觀點,性能測試不能相信道聽途說,得通過實驗去分析。
『叄』 如何保證緩存與資料庫雙寫時的數據一致性
一般來說,就是如果系統不是嚴格要求緩存+資料庫必須一致性的話,緩存可以稍微的跟資料庫偶爾有不一致的情況,最好不要做這個方案,讀請求和寫請求串列化,串到一個內存隊列里去,這樣就可以保證一定不會出現不一致的情況
串列化之後,就會導致系統的吞吐量會大幅度的降低,用比正常情況下多幾倍的機器去支撐線上的一個請求。
『肆』 mysql 如何解決數據一致性
MySQL主從復制
現在常用的MySQL高可用方案,十有八九是基於 MySQL的主從復制(replication)來設計的,包括常規的一主一從、雙主模式,或者半同步復制(semi-sync replication)。
我們常常把MySQL replication說成是MySQL同步(sync),但事實上這個過程是非同步(async)的。大概過程是這樣的:
在master上提交事務後,並且寫入binlog,返回事務成功標記;
將binlog發送到slave,轉儲成relay log;
在slave上再將relay log讀取出來應用。
步驟1和步驟3之間是非同步進行的,無需等待確認各自的狀態,所以說MySQL replication是非同步的。
MySQL semi-sync replication在之前的基礎上做了加強完善,整個流程變成了下面這樣:
首先,master和至少一個slave都要啟用semi-sync replication模式;
某個slave連接到master時,會主動告知當前自己是否處於semi-sync模式;
在master上提交事務後,寫入binlog後,還需要通知至少一個slave收到該事務,等待寫入relay log並成功刷新到磁碟後,向master發送「slave節點已完成該事務」確認通知;
master收到上述通知後,才可以真正完成該事務提交,返回事務成功標記;
在上述步驟中,當slave向master發送通知時間超過rpl_semi_sync_master_timeout設定值時,主從關系會從semi-sync模式自動調整成為傳統的非同步復制模式。
半同步復制看起來很美好有木有,但如果網路質量不高,是不是出現抖動,觸發上述第5條的情況,會從半同步復制降級為普通復制;此外,採用半同步復制,會導致master上的tps性能下降非常嚴重,最嚴重的情況下可能會損失50%以上。
這樣來看,除非需要非常嚴格保證數據一致性等迫不得已的場景,就不太建議使用半同步復制了。當然了,事實上我們也可以通過加強程序端的邏輯控制,來避免主從數據不一致時發生邏輯錯誤,比如說如果在從上讀取到的數據和主不一致的話,那麼就觸發主從間的一次數據修復工作。或者,我們也可以用 pt-table-checksum & pt-table-sync 兩個工具來校驗並修復數據,只要運行頻率適當,是可行的。
真想要提高多節點間的數據一致性,可以考慮採用PXC方案。現在已知用PXC規模較大的有qunar、sohu,如果團隊里初期沒有人能比較專注PXC的話,還是要謹慎些,畢竟和傳統的主從復制差異很大,出現問題時需要花費更多精力去排查解決。
如何保證主從復制數據一致性
上面說完了非同步復制、半同步復制、PXC,我們回到主題:在常規的主從復制場景里,如何能保證主從數據的一致性,不要出現數據丟失等問題呢?
在MySQL中,一次事務提交後,需要寫undo、寫redo、寫binlog,寫數據文件等等。在這個過程中,可能在某個步驟發生crash,就有可能導致主從數據的不一致。為了避免這種情況,我們需要調整主從上面相關選項配置,確保即便發生crash了,也不能發生主從復制的數據丟失。
1. 在master上修改配置
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
上述兩個選項的作用是:保證每次事務提交後,都能實時刷新到磁碟中,尤其是確保每次事務對應的binlog都能及時刷新到磁碟中,只要有了binlog,InnoDB就有辦法做數據恢復,不至於導致主從復制的數據丟失。
2. 在slave上修改配置
master_info_repository = "TABLE"
relay_log_info_repository = "TABLE"
relay_log_recovery = 1
上述前兩個選項的作用是:確保在slave上和復制相關的元數據表也採用InnoDB引擎,受到InnoDB事務安全的保護,而後一個選項的作用是開啟relay log自動修復機制,發生crash時,會自動判斷哪些relay log需要重新從master上抓取回來再次應用,以此避免部分數據丟失的可能性。
通過上面幾個選項的調整,就可以確保主從復制數據不會發生丟失了。但是,這並不能保證主從數據的絕對一致性,因為,有可能設置了ignoredo ewrite等replication規則,或者某些SQL本身存在不確定因素,或者人為在slave上修改數據,最終導致主從數據不一致。這種情況下,可以採用pt-table-checksum和pt-table-sync工具來進行數據的校驗和修復。
『伍』 Redis 如何保持和 MySQL 數據一致
redis在啟動之後,從資料庫載入數據。
讀請求:
不要求強一致性的讀請求,走redis,要求強一致性的直接從mysql讀取
寫請求:
數據首先都寫到資料庫,之後更新redis(先寫redis再寫mysql,如果寫入失敗事務回滾會造成redis中存在臟數據)
在並發不高的情況下,讀操作優先讀取redis,不存在的話就去訪問MySQL,並把讀到的數據寫回Redis中;寫操作的話,直接寫MySQL,成功後再寫入Redis(可以在MySQL端定義CRUD觸發器,在觸發CRUD操作後寫數據到Redis,也可以在Redis端解析binlog,再做相應的操作)
在並發高的情況下,讀操作和上面一樣,寫操作是非同步寫,寫入Redis後直接返回,然後定期寫入MySQL
1.當更新數據時,如更新某商品的庫存,當前商品的庫存是100,現在要更新為99,先更新資料庫更改成99,然後刪除緩存,發現刪除緩存失敗了,這意味著資料庫存的是99,而緩存是100,這導致資料庫和緩存不一致。
解決方法:
這種情況應該是先刪除緩存,然後在更新資料庫,如果刪除緩存失敗,那就不要更新資料庫,如果說刪除緩存成功,而更新資料庫失敗,那查詢的時候只是從資料庫里查了舊的數據而已,這樣就能保持資料庫與緩存的一致性。
2.在高並發的情況下,如果當刪除完緩存的時候,這時去更新資料庫,但還沒有更新完,另外一個請求來查詢數據,發現緩存里沒有,就去資料庫里查,還是以上面商品庫存為例,如果資料庫中產品的庫存是100,那麼查詢到的庫存是100,然後插入緩存,插入完緩存後,原來那個更新資料庫的線程把資料庫更新為了99,導致資料庫與緩存不一致的情況
解決方法:
遇到這種情況,可以用隊列的去解決這個問,創建幾個隊列,如20個,根據商品的ID去做hash值,然後對隊列個數取摸,當有數據更新請求時,先把它丟到隊列里去,當更新完後在從隊列里去除,如果在更新的過程中,遇到以上場景,先去緩存里看下有沒有數據,如果沒有,可以先去隊列里看是否有相同商品ID在做更新,如果有也把查詢的請求發送到隊列里去,然後同步等待緩存更新完成。
這里有一個優化點,如果發現隊列里有一個查詢請求了,那麼就不要放新的查詢操作進去了,用一個while(true)循環去查詢緩存,循環個200MS左右,如果緩存里還沒有則直接取資料庫的舊數據,一般情況下是可以取到的。
1、讀請求時長阻塞
由於讀請求進行了非常輕度的非同步化,所以一定要注意讀超時的問題,每個讀請求必須在超時間內返回,該解決方案最大的風險在於可能數據更新很頻繁,導致隊列中擠壓了大量的更新操作在裡面,然後讀請求會發生大量的超時,最後導致大量的請求直接走資料庫,像遇到這種情況,一般要做好足夠的壓力測試,如果壓力過大,需要根據實際情況添加機器。
2、請求並發量過高
這里還是要做好壓力測試,多模擬真實場景,並發量在最高的時候QPS多少,扛不住就要多加機器,還有就是做好讀寫比例是多少
3、多服務實例部署的請求路由
可能這個服務部署了多個實例,那麼必須保證說,執行數據更新操作,以及執行緩存更新操作的請求,都通過nginx伺服器路由到相同的服務實例上
4、熱點商品的路由問題,導致請求的傾斜
某些商品的讀請求特別高,全部打到了相同的機器的相同丟列里了,可能造成某台伺服器壓力過大,因為只有在商品數據更新的時候才會清空緩存,然後才會導致讀寫並發,所以更新頻率不是太高的話,這個問題的影響並不是很大,但是確實有可能某些伺服器的負載會高一些。
img
搜索微信號(ID:芋道源碼),可以獲得各種 Java 源碼解析。
並且,回復【書籍】後,可以領取筆者推薦的各種 Java 從入門到架構的書籍。
『陸』 請教redis如何做到和mysql資料庫的同步
二者數據同步的關鍵在於mysql資料庫中主鍵,方案是在redis啟動時區mysql讀取所有表鍵值存入redis中,往redis寫數據是,對redis主鍵自增並進行讀取,若mysql更新失敗,則需要及時清除緩存及同步redis主鍵。
參考代碼如下:
String tbname = "login";
//獲取mysql表主鍵值--redis啟動時
long id = MySQL.getID(tbname);
//設置redis主鍵值--redis啟動時
redisService.set(tbname, String.valueOf(id));
System.out.println(id);
long l = redisService.incr(tbname);
System.out.println(l);
Login login = new Login();
login.setId(l);
login.setName("redis");
redisService.hmset(String.valueOf(login.getId()), login);
boolean b = MySQL.insert("insert into login(id,name) values(" + login.getId()
+ ",'" + login.getName() + "')");
/**
*
* 隊列處理器更新mysql失敗:
*
* 清除緩存數據,同時主鍵值自減
*/
if (!b)
{
redisService.delKeyAndDecr
(tbname, "Login:"+String.valueOf(login.getId()));
// redisService.delete("Login:"+String.valueOf(login.getId()));
//redisService.decr(tbname);
}
System.out.println(redisService.exists("Login:"+String.valueOf(login.getId())));
System.out.println(redisService.get(tbname));
『柒』 怎樣理解mysql中的一致性
定義:資料庫一致性(Database Consistency)是指事務執行的結果必須是使資料庫從一個一致性狀態變到另一個一致性狀態。
資料庫狀態如何變化?每一次數據變更就會導致資料庫的狀態遷移。如果資料庫的初始狀態是C0,第一次事務T1的提交就會導致系統生成一個SYSTEM CHANGE NUMBER(SCN),這是資料庫狀態從C0轉變成C1。執行第二個事務T2的時候資料庫狀態從T1變成T2,以此類推,執行第Tn次事務的時候資料庫狀態由C(n-1)變成Cn。
定義一致性主要有2個方面,一致讀和一致寫。
一致寫:事務執行的數據變更只能基於上一個一致的狀態,且只能體現在一個狀態中。T(n)的變更結果只能基於C(n-1),C(n-2), ...C(1)狀態,且只能體現在C(n)狀態中。也就是說,一個狀態只能有一個事務變更數據,不允許有2個或者2個以上事務在一個狀態中變更數據。至於具體一致寫基於哪個狀態,需要判斷T(n)事務是否和T(n-1),T(n-2),...T(1)有依賴關系。
一致讀:事務讀取數據只能從一個狀態中讀取,不能從2個或者2個以上狀態讀取。也就是T(n)只能從C(n-1),C(n-2)... C(1)中的一個狀態讀取數據,不能一部分數據讀取自C(n-1),而另一部分數據讀取自C(n-2)。
『捌』 技術分享 | 兩個單機 MySQL 該如何校驗數據一致性
業務有兩個 MySQL 集群是通過 MQ 進行同步的,昨晚 MQ 出現異常,報了很多主鍵沖突,想請 dba 幫忙校驗一下兩個集群的數據是否一致。
當接到這個需求的時候並沒當回事,隱約有點印象 pt-table-checksum 能通過 dsn 實現 MySQL 的數據校驗,所以當時就應承下來了。不曾想,啪啪打臉,回想起來真是草率了。
本文參考的是 pt-table-checksum 的校驗邏輯,基於數據塊去遍歷每個表,然後比對 checksum 的值判斷該塊是否一致,本文主要是想聊聊我在實現數據校驗腳本過程中遇到的問題以及解決思路,希望對大家有幫助。
利用線上的配置文件搭建一套主從環境。
這個用例將通過 dsn 方式連接從庫。
這個用例將通過 dsn 方式連接從庫,但是會將從庫的復制鏈路 stop 掉,並清空復制信息。
熟悉 pt-table-checksum 的朋友應該都知道,該工具是基於主鍵(非空唯一鍵)進行掃描數據行,其實這個邏輯針對整型單列主鍵實現起來很簡單,但是如果是聯合主鍵且是字元型,好像就沒那麼簡單了,有興趣的可以思考一下。下面我先說一下大致的邏輯:
第一步:判斷 _min_rowid 是否為空,為空就取該表的第一行,並記作 _min_rowid 。
第二步:根據 _min_rowid 作為條件進行掃描該表,取下一個數據塊的數據,記錄數據塊的最後一行數據的主鍵值,記錄 checksum 的值,並記下 _min_rowid 。
第三步:判斷_min_rowid是否為空,非空重復第二步,為空退出檢查。
通過上述三個步驟可以看到,如果是單列整型的主鍵,實現起來很簡單,但是問題來了,業務的表的主鍵五花八門,有的是聯合主鍵,有的是字元型的聯合主鍵,還有整型+字元型的聯合主鍵,那麼上述的實現方式顯然是有問題的。所以實現起來需要多考慮幾個問題:
鑒於存在上述兩個問題,可以參考如下實現邏輯:
假如有這么一個聯合主鍵欄位 primary key(a,b,c) 都是整型,該如何編寫遍歷 sql 呢?起初我的想法很簡單,具體如下:
至此在編寫校驗腳本過程遇到的兩個問題就算告一段落了,剩下的就是各種邏輯處理了,不過多贅述,有興趣的可以自行閱讀腳本文件。
本著最低程度影響業務,所以取消加鎖邏輯。但是又要保證該數據塊的數據一致性,如果這個數據塊是個熱數據,當前正在變更,那麼校驗的時候難免會不一致。所以只能通過多次校驗實現,默認是校驗20次,其中有一次校驗結果是一致,就認為是一致的,如果前5次校驗過程中,這個數據塊的數據沒有變化,也視為不一致(可能是因為延遲,也可能是真的不一致)。
pt-table-checksum 不校驗表結構,改寫時添加表結構的校驗。
可以基於表的並行校驗,可由用戶指定並行數,但是腳本有個安全機制,如果用戶指定的並行數大於當前 cpu 空閑核心數,就會按當前(空閑核心數-1)作為並行數。
添加網路監控,由用戶指定網路上限百分比,當網卡流量超過這個百分比就暫停任務,等待網卡流量低於閾值才會繼續任務。這個主要是出於對於中間件(mycat)的場景或者分布式資料庫(tidb)的場景。
支持定時任務功能,用戶可以使用這個功能規避業務高峰,僅在業務低峰進行數據校驗。
不僅限於主從節點的校驗,只要目標對象支持 MySQL 的標准 SQL 語法就能做數據校驗。
校驗邏輯是通過 SQL 採集目標節點的資料庫,如果目標資料庫系統當前存在異常,無疑是雪上加霜,將會觸發未知問題,所以添加超時機制,單次取數據塊的閾值是5s,超過5秒就放棄等待重試。測試發現,有時候即便觸發超時了,但是 SQL 任務還是會在目標資料庫的 processlist 中能看到,所以又添加了一個 kill 機制,超時後會觸發一個 kill processlist id 的動作。另外為了避免 kill 錯,在每個 SQL 對象添加了一個32位的 md5 值,每次 kill 的時候會校驗這個 md5 值。
本工具借鑒 pt-table-checksum 工具思路改寫,可以檢查隨意兩個 mysql(支持 mysql sql 語法的資料庫)節點的數據一致性。
基於主鍵以一個塊遍歷數據表,比對checksum的值,塊的大小可通過參數指定。 (1)獲取該表的第一個數據塊的查詢SQL。 (2)將兩個目標節點的數據塊的checksum的值,記錄到臨時文件,file1 file2。 (3)比對file1 file2是否一致。
第一步:先開啟一個 screen 監控網路
第二步:新開啟一個screen執行校驗任務
(1)info.log 文件
(2)list目錄
(3)md5 目錄
(4)pri 目錄
(5)res 目錄
這是 table 目錄下記錄某個數據塊不一致的一個例子
這是 diff 目錄下記錄某個數據行不一致的一個例子
(6)skip.log 文件
本工具是參考了 pt-table-checksum 工具的一些思路並結合自身經驗進行改寫,尚有很多不足之處,僅做學習交流之用, 如有線上環境使用需求,請在測試環境充分測試。
『玖』 2020-05-16:如何保證redis和mysql數據一致
保證一致性的做法就是用某種分布式協議一致性來做:
1、SAGA或者TCC - 這兩種需要業務代碼的大量配合。通過業務代碼來補償一致性。
2、 現實當中有XA協議。比如Ehcache是支持XA協議的。但是性能表現不佳,運維也麻煩。
3、基於Paxos或者Raft的分布式鎖,然後對Redis和DB進行雙寫
『拾』 如何保證redis集群和mysql的數據一致性
如何保證redis集群和mysql的數據一致性
如果要「保證」數據的安全性,那麼會帶來開銷的進一步提升,以至於使用redis帶來的性能優勢都會喪失。正確的做法是區分不同的業務,使得並不需要「保證」數據一致性的場合,可以使用redis優化。而敏感的場合依然使用mysql。