談一談分佈式系統中數據的安全和性能

在分佈式系統中,咱們知道CAP定理BASE理論,數據的安全和性能是負相關的,數據的安全性提升了,那他的性能就會降低,相關,他的性能提升了,數據的安全性就會降低。咱們從幾個中間件來討論這個問題。mysql

mysql

當mysql性能出現瓶頸時,咱們會作分庫分表、讀寫分離等,讀寫分離須要咱們作主從複製,對讀的操做,咱們指向從庫,對寫的操做,咱們指向主庫,下面看看主從複製的原理。
當業務系統提交數據的時候,master會將這變動的數據保存到binlog文件,寫入成後,事務提交成功。
slave中會有一個線程,他會從master中讀取binlog信息,而後寫入relay文件。而後他還會有其餘線程,讀取relay文件的信息,把這個信息從新在slave庫執行一遍。也就是說,若是在master中執行了一個update的語句,那在slave中一樣也執行如出一轍的update語句,這樣兩邊的數據就會保持一致,因爲master先執行,而後slave再執行,因此會有稍微的延遲。若是執行的語句比較久,那這個延時也會比較長,固然系統的壓力也會影響延遲的時間。
image.png
除了延時之外,他還有一個比較大的問題,當寫入binlog後,表明事務提交成功,此時master掛了,致使slave沒辦法讀取這部分的binlog,因此就會出現數據的丟失,兩邊的數據就沒辦法保持一致性,因此咱們一般會把上面的異步複製形式設置半同步複製,也就是semi-sync。
半同步複製與異步複製不一樣的是,當master寫入到binlog後,他會主動的把數據同步到從庫,從庫把信息寫入到relay文件,會返回ACK給master,此時master纔會認爲他的事務是提交的。
image.png
若是有多個slave的狀況,則至少返回1個ACK才認爲事務的提交的。半同步複製雖然解決了數據安全的問題,可是他須要從庫寫入relay文件並返回ACK纔算提交事務,與異步複製對比,他的性能是降低的。redis

單體

在單體中,也一樣存在着數據安全和性能的負相關問題。
這裏簡述一下mysql對update語句的一個流程。sql

  • 當執行update的時候,會先從磁盤裏把數據讀取到緩存。
  • 寫入undo文件,這裏是在咱們事務回滾的時候用的。
  • 修改緩存數據,好比把id爲1的name由張三改成李四。
  • 寫入redo緩存,redo主要是爲了宕機重啓時,恢復數據用的。
  • 寫入redo緩存後,寫入到磁盤。
  • 寫入binlog文件。
  • 寫入binlog後,提交commit給redo,跟redo說已經寫入到binlog了。
  • 按期把緩存的數據寫入到磁盤。

image.png
咱們對數據的更新,都是在緩存中進行的,這樣能夠保證性能的提升。同時爲了數據的安全性,還引入了undo、redo、binlog等東西。咱們能夠看redo和binlog兩種寫入磁盤的策略。
在redo中,咱們能夠選擇0,即不把緩存數據寫入磁盤,這樣能夠快速執行完redo操做,若是此時宕機了,還沒寫入磁盤的數據就丟失了,雖然提升了性能,可是數據安全性沒有了。若是選擇1,因爲要寫入磁盤才能夠完成redo操做,雖然保證了數據的安全性,可是性能卻降低了。
一樣的,binlog寫入oscache是提升了性能,可是服務器宕機會致使oscache的數據不能及時的寫入磁盤,致使數據的安全性沒有。若是直接寫入磁盤,性能又降低。segmentfault

redis

與mysql已有,redis的複製也是異步複製的,當業務系統往master寫入數據的時候,他就會經過異步複製的方式把數據同步給slave,因此和mysql相似,當業務系統認爲他已經把數據寫入到redis的時候,此時master掛了,可是數據還沒同步到slave,他的數據就丟失了。
image.png
另一個場景,就是發生了腦裂,也就是sentinel認爲master掛了,而後從新選舉了master,此時業務系統和master是正常通信的,他把數據提交到原master節點,可是原master節點的數據此時是沒辦法同步到其餘節點,致使數據不一致。
image.png
在這狀況下,咱們會作如下配置:緩存

min-replicas-to-write 1
min-replicas-max-lag 10

這個意思是至少有1個slave已經有10秒沒有同步,則master暫停接收請求。因此不會說master一直寫入數據,而slave沒有同步。若是發生以上兩個場景,最多丟失10秒的數據。雖然沒有嚴格的作到數據安全性,可是也保證了數據的不一致性不會超過10秒,超過10秒後,因爲不能寫數據,寫性能降低爲0。安全

RocketMQ

咱們看看基於Dledger是怎麼作broker同步的。
image.png
首先,master broker收到消息後,會把這個消息置爲unconmmited狀態,而後把這個消息發送給slave broker,slave broker收到消息後,會發送ack進行確認,若是有多個slave broker,當超過一半的slave broker發送ack時,master broker纔會把這個消息置爲committed狀態。在這種機制下,保證了數據的安全性,當master broker掛了,咱們還有至少超過一半的slave broker的數據是完整的,因爲須要多個slave broker進行ack確認,也下降了性能。
從單體上來講,異步刷盤和同步刷盤跟mysql的redo寫入磁盤的同樣的。
另外,kafka的同步機制跟這個相似,並且他也有寫入oacache的操做。服務器

Zookeeper

Zookeeper是CP模型的,那他的數據安全性是能夠保證的,那他的性能呢?咱們假設此時master節點掛了,此時須要從新選主,這個時候Zookeeper集羣是不可用狀態的。那Zookeeper是如何保證數據的一致性呢?
image.png
咱們假設master同步給5個slave。
當master不用確認是否已經同步給slave就直接返回,這個時候性能是最高的,可是安全性是最低的,由於master數據沒同步到slave的時候掛了,那這個數據是丟失的。
當master確認已經同步給全部slave(這裏是5個)才返回,這個時候,性能是最低的,可是安全性是最高的,由於無論哪一個slave,他的數據都是完整的。
不論是RocketMQ仍是Zookeeper,都是折中選擇超過一半的slave同步,纔算成功。當咱們訪問Zookeeper的時候,他會根據已經同步好的slave服務器讓咱們來讀取對應的信息,這樣咱們讀取的數據確定都是最新的。異步

相關文章
相關標籤/搜索