高並發的情況下(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之類的日誌系統。首先要明確下需求。
- 讀高並發,完全不影響mysql寫入,事實上大部分讀並發高,寫並發低的需求,都可以直接操作mysql,進行redis/mysql雙寫,當然讀的時候不是雙讀。
- 寫高並發,除了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有什麼區別?