高並發的情況下(100W),數據先存在Redis保證快速響應,然後怎麼往MySql裡面寫?


因為還沒有寫入MySQL,所以你在把數據寫入Redis時,需要設計一個key來唯一標識一條數據.

MySQL表中應該設置一個唯一欄位用於存儲這個key.

這個key可以是一個由程序即時生成的隨機唯一值,比如可以取Linux提供的uuid:

/proc/sys/kernel/random/uuid

取到後用sadd添加到Redis的集合(元素唯一)里.

添加成功,表示集合中沒有這個uuid,在集合里是唯一的.

然後再把這個uuid用lpush添加到Redis的列表(元素有序)里.

lpush入隊後,當列表的長度大於等於N(自定義數值)時,Redis用lrange取出列表裡的元素並批量寫入到MySQL,寫入成功後用ltrim刪掉列表中已經處理的元素.

優化就體現在:原來的即時寫入轉變為批量寫入.

風險是:Redis意外崩潰有可能丟數據.

比如你的Redis配置了 appendfsync everysec

那就有丟失前1秒數據的風險.


12306改用mysql了?

不是12306,那你那裡來的1000k的並發寫?


數據放消息隊列啊,放redis怎麼找回來往資料庫寫?自己實現一個基於redis的消息隊列?


看你是什麼場景,

讀多 還是 寫多

讀取的數據需不需要很實時

數據寫入是不是一定要即時並無延時無誤

數據寫入的入口多不多,能否保證全部都會按要求同時寫redis和MySQL


這麼設計也是很獨特。

既然redis已經存了,那就用redis好了,redis本身是可以支持持久化的,為什麼最終還要寫到資料庫呢?

這麼設計還會有個問題,資料庫的數據會不一致。比如客戶端已經寫入了一個數據,但之後立即去資料庫查詢,會發現查詢不到,因為此時數據還在redis。

有些場景下,這會是一個很嚴重的問題,比如庫存管理,訂單管理。但貌似題主不可能是庫存和訂單,這麼大並發的庫存和訂單,題主公司要賺翻了。這只是給個例子,此重場景下,此方案不可用。

如果如果題主是日誌之類的非實時場景,可以考慮kafka之類的日誌系統。


首先要明確下需求。

  1. 讀高並發,完全不影響mysql寫入,事實上大部分讀並發高,寫並發低的需求,都可以直接操作mysql,進行redis/mysql雙寫,當然讀的時候不是雙讀。
  2. 寫高並發,除了mysql分庫分表寫,暫時沒想到好辦法。原因是mysql本身不適用於讀寫高並發需求場景,關係型資料庫的高並發一直是業內不看好的。大多數高並發解決方案是把數據關係處理放到邏輯層中,而資料庫中存儲的都是非關係的數據,這種場景的話,沒有必要用mysql。

順便,看了下你這裡的需求類似於「註冊中心」的概念,這種大型繁忙讀寫的業務,一般後端數據都非常輕量。對於這種大規模實時狀態更新必須在 性能(並發量)、 數據一致性、可靠性 中有所取捨。一般看來是捨棄強一致性,而取性能跟可靠性。

方案是集群部署,然後在不同節點之間進行數據傳遞保證一致性,類似的老牌開源框架是zookeeper,更輕量級的是etcd。其他的也有很多,題主可以從中找點啟發。


搭一個kafka集群,數據寫到redis的同時丟到集群中,後面可以起一堆服務非同步的往資料庫寫。

這種情況下,數據可以分庫,可以按id讓不同的數據落入到不同的庫中。為了保證擴展性,落庫策略可以用一致性哈希處理一下。


假設這裡高並發是指高並發寫:

1. 看下數據的屬性,如果數據冷熱明顯,非同步本身已經帶來很多的合併(同一個數據項的多次修改只寫一次 mysql);使用 batch write,最終到 mysql 的 tps 會有效降低。

2. 嘗試估算上面的 tps 值(拍腦袋、壓測、...),準備 mysql 資源。mysql 水平擴已經有很成熟的方案,可以做到對應用基本透明。

另外,這個模型(寫入 redis 即返回成功,由另外的流程同步到 mysql)讀寫都由 redis 完成,redis 承擔了 db 的職責,而 mysql 只能算是冷備


100w、、、、嚇死了

身在十八線互聯網哪裡見過這個大的數據量!

寫的話一般常見的用RabbitMQ ActiveMQ+MySQL分表

讀的話 交給redis吧、、、


目前高並發的處理一般都是選用限流+隊列+非同步,放到消息隊列中間件要比redis實現的消息隊列更可靠。

根據業務場景選擇對應的隊列

強一致性的消息可選擇:RabbitMq、ActiveMQ可以持久化消息、隊列

消息丟不丟失無所謂,可以選擇kafka。性能吊炸天

隊列的單個消費者可以開啟多線程 + 集群

這樣的話基本碼機器就行了。最後的瓶頸會到消息隊列。優化隊列即可,分散式隊列是一個解決方案


我對問題的理解:是讀高並發達到100w,寫並發可能不到1/100(畢竟100w並發寫的應用很少),題主希望做到數據一致性和高可用性。如果是這個需求,要做到高可用性,使用redis並不是好方案,我建議在邏輯層進行分庫,根據不同數據入不同庫,再在不同庫所在伺服器間做主從備份。只要在邏輯層控制好庫的切換可以做到比較好的平衡。迷戀不可軟體不如用最暴力簡單的方法。


看資料庫實例部署方式了,硬體很重要,然後就是分庫,如果非同步寫,100w可以batch操作,算下來寫庫呢tps也沒多高


首先,我覺得題主的問題並沒有交代明白需求是什麼? (樓主的提出的是「要求」,不是「需求」,題主要求是存redis然後往mysql寫)

但是,需求和要求是有區別的,不同的需求有不同的做法,隨意猜想題主可能的需求:

在數據被寫入後可以快速響應的前提下,同時滿足下面一個需求

(1)是為了更可靠的持久化

(2)還是轉換存儲形式方便sql查詢

題主可以先明確一下「需求」(not 「要求」),再繼續回答:)

對於需求(1)

對於需求(2)


用redis緩存sql語句。如果是insert和del的話,用list。然後如果是update的話,用redis的hash表存mysql語句,每個語句有個key。key可以用mysql的表名加鍵值的方式保證唯一,這樣可以合併update語句。然後另外一個進程讀取寫入mysql。每次讀取這個表的時候,rename老表,然後讀新表。


-首選建議是棄了MySQL,作為(免費開源的)關聯資料庫,MySQL實在不是相應高並發讀寫的適宜工具。專門的事情用專用的工具做才是事半功倍的首選。將高並發的部分移入專門的NoneSQL資料庫(e.g. Cassandra) 會是首要推薦。

如果實在離不了MySQL,用Redis來實現緩存略顯複雜。

  • 首先你得保證Redis高可用性。這個有現成的解決方案,例如Gitlab有官方貼(Redis · High availability · Administration · Help)
  • 需要在系統里實現日誌系統,要保證多用戶並發寫衝突可以用日誌系統穩定重建出數據,而不會出現Redis與MySQL不一致的情況。(這點在分布計算場景中甚有難度,哪怕使用外部隊列系統如Kafka,因為寫Redis與寫Kafka之間的延遲,可能出現先寫完Redis的主機後寫入Kafka的情況。目測需要加一個Optimistic Locking)
  • 然後你要保證多次寫同一記錄不會造成系統問題,Consistent Hashing估計跑不了
  • 高可用的隊列系統,可以起Kafka。當然有了上一條自己起幾個主機反覆寫直到成功為止也是可以的。

綜上所述,用Redis作MySQL寫緩存不是不能做,但是想要同時大量寫並發需要很多額外工序才能保證穩定無錯。考慮將這部分數據挪到Cassandra之類的NonSQL資料庫可能是更簡單的解決方案。


用個非同步隊列慢慢同步 MYSQL就好了

首先100%保證 Redis 高可用

存入Redis的同時,丟一分數據到Kafka,然後 自己處理 Kafka 跟Mysql數據的寫入(如果你不要求高一致性 的話KAFKA是不錯的選擇。)


這個和Redis的關係不大吧?想緩解MySQL 壓力,接入服務把數據寫入隊列緩存,用一個消費隊列數據的服務寫MySQL 。


推薦閱讀:

這句sql語句怎麼理解?
在SQL中,如何查詢某一欄位中最大值的數據?
你遇到過哪些MySQL的坑?
mysql索引最左匹配原則的理解?
is NULL和= NULL,is not NULL和!= NULL有什麼區別?

TAG:MySQL | Redis | 高並發 | JavaEE |