JAVA基礎
JVM
設計模式
技術棧
Redis(Remote Dictionary Server(遠程數據服務))緩存
Redis是基於內存的高速緩存key-value數據庫(C語言開發)
優點:
1.基於內存讀寫速度快,可以支持高性能的業務場景
2.支持豐富的數據結構(String,hash,set,list,sort)
3.QPS可以達10萬+
缺點:
- 數據不一致
- 緩存雪崩
- 緩存穿透
- 緩存併發
- 數據庫容量受到物理內存的限制,不能用作海量數據的高性能讀寫
數據不一致問題(mysql+redis)
業界方案:監聽mysql的binlog日誌,異步淘汰緩存
緩存雪崩(大量緩存同時失效,導致直接查DB,導致DB壓力太大奔潰)
業界方案:將熱點數據設置不同的過期時間,以防止同時查詢熱點數據給數據庫帶來壓力
緩存穿透(針對用戶惡意攻擊)
在查詢緩存沒有值,再查詢mysql也沒有值時,會將此key的value設置爲null,並添加六十秒過期時間
業界方案:布隆過濾器(存在誤算率,隨着存入的元素數量增加,誤算率也隨着增加)
布隆過濾器的思想:核心是實現了一個超大的位數組和幾個哈希函數,每一個元素,都調用這幾個哈希函數算出哈希值,並落到這個數組中,隨着元素的增加,哈希值的相似度就會升高,誤判率就會出現
Redis熱點key的尋找方案
redis於4.0.3版本開始正式支持基於LFU的熱點key發現機制。
Least Frequently Used——簡稱LFU,意爲最不經常使用,是redis4.0新增的一類內存逐出策略,從LFU的字面意思我們很容易聯想到key的訪問頻率,並對訪問頻率進行了統計
可以對概率因子和衰減因子進行配置,推薦使用redis的默認值即可:
lfu-log-factor 10
lfu-decay-time 1
要注意需要先把內存逐出策略設置爲allkeys-lfu或者volatile-lfu,否則會返回錯誤
redis 4.0.3同時也提供了redis-cli的熱點key發現功能,執行redis-cli時加上–hotkeys選項即可,示例如下:$./redis-cli –hotkeys 排在前面就是熱點key
Redis和Memcache對比
|
Redis |
Memcache |
數據結構 |
多種數據結構:String,hash,set,list,sort |
Key-value |
集羣模式 |
Redis自帶(redis cluster) |
客戶端自己實現 |
線程模式 |
單線程(小數據量性能好,可以持久化) |
多線程(大數據量100M性能好,不能持久化) |
MQ(Message Queue)消息隊列
MQ:是一種應用程序對應用程序傳遞消息的中間件,是通過讀寫出入隊列來通信。
三種通訊模式 1.點對點,2.多點廣播,3.發佈和訂閱(一般用這個)
優點:
1.異步:執行失敗重試,提高接口的性能(失效策略;數據回補)
2.解耦:利用MQ降低系統的耦合性(系統重構)
3.削峯:將一些無需及時返回且耗時的操作提取出來,進行異步處理,從而節省服務器的響應時間來提高系統的吞吐量(秒殺,公司的活動:搶金幣)
缺點:
1.MQ一旦掛了,整個系統就奔潰了(高可用)
2.系統的複雜度提高(消息堆積)
3.數據不一致(消息重複,消息順序,消息丟了)
如何選型:RabbitMQ,RocketMQ,Kafka
Kafka是主要用於配合大數據類的系統來進行實時數據計算、日誌採集等場景(主要支持簡單的MQ功能)
我們一般在RabbitMQ和RocketMQ中間來選擇
選擇RocketMQ的理由(阿里出品):
1.topic可以達到幾百,幾千個的級別,吞吐量會有較小幅度的下降(RabbitMQ會大幅下降)
2.分佈式集羣,每個部分都可以水平擴展(RabbitMQ主從集羣)
3.java開發(RabbitMQ用erlang語言開發)
4.吞吐量是10萬級(RabbitMQ是萬級)
缺點:
1.延時毫秒級(RabbitMQ是微秒級)
2.社區活躍度一般(RabbitMQ比較好版本迭代特別快)
MQ的高可用
RabbitMQ是鏡像集羣模式(主從)
Kafka是分佈式集羣(副本集,HA),每個節點都有一個replicate備份。讀寫都在leader節點
RocketMQ是分佈式集羣如下
Name Server:主要提供輕量級查找和路由服務(保存了其它三部分的信息)(各個節點之間不通信)
Broker Cluster:輕量的topic和queue機制(消息的存儲,支持push和pull)
Product Cluster:分佈式的producers通過負載均衡模型向broker發送消息
Consumer Cluster:支持push,pull,支持集羣消費與消息廣播同時提供實時訂閱
MQ的消息冪等性(不重複)
造成的原因:1.系統重啓 2.網絡異常 3.消費失敗
解決方案
- 消息的唯一標識存入redis中並進行判斷
- 數據庫的存儲判斷
MQ丟消息
- producter:發送消息狀態超時或者失敗,則會觸發默認的2次重試(支持日誌的索引查找)
- broker:是一主多從的節點,同時支持同步和異步刷盤的策略,保證消息落到本地內存中,消息也支持持久化到commitlog裏面,即使宕機,未消費的消息也可以加載出來
- consumer:確保拉取到的消息成功消費,consumer自身維護了一個持久化的offset,消費成功後纔會更新自己的offset,offset會持久化到本地,即使consumer掛掉重啓之後可以繼續拉取offset之前的消息到本地
MQ消息的積壓
策略:超出了buffer,也可以丟棄,然後再從CommitLog中補數據
打開rocketmq的控制檯查看是歷史消費記錄,如果是消息寫入速度大於消息的消費速度,調整業務代碼或對消費者進行擴容
Consumer消費消息出現問題,只能操作臨時緊急擴容了,具體操作步驟和思路如下:
1)先修復consumer的問題,確保其恢復消費速度,然後將現有cnosumer都停掉
2)新建一個topic,partition是原來的10倍,臨時建立好原先10倍或者20倍的queue數量
3)然後寫一個臨時的分發數據的consumer程序,這個程序部署上去消費積壓的數據,消費之後不做耗時的處理,直接均勻輪詢寫入臨時建立好的10倍數量的queue
4)接着臨時徵用10倍的機器來部署consumer,每一批consumer消費一個臨時queue的數據
5)這種做法相當於是臨時將queue資源和consumer資源擴大10倍,以正常的10倍速度來消費數據
6)等快速消費完積壓數據之後,得恢復原先部署架構,重新用原先的consumer機器來消費消息
MQ消息的順序
避開這種使用場景
數據庫
Mysql事務默認(可重複讀)
事務隔離級別 |
髒讀 |
不可重複讀 |
幻讀 |
讀未提交(read-uncommitted) |
是 |
是 |
是 |
不可重複讀(read-committed) |
否 |
是 |
是 |
可重複讀(repeatable-read) |
否 |
否 |
是 |
串行化(serializable) |
否 |
否 |
否 |
髒讀:一個事務讀到另一個事務未提交的更新數據
幻讀:已提交的插入數據
mysql默認的事務隔離級別爲repeatable-read
網絡
URL解析統一資源定位符 (Uniform Resource Locator, URL)
調用鏈路
http://www.baidu.com(scheme:通信協議, host:主機, port:端口號)
DNS解析(DNS緩存)
TCP連接
發送http請求
服務器處理請求並返回http報文
瀏覽器解析渲染頁面
連接結束
思考
秒殺設計思路
用戶量不大的策略
隊列+redis全局計數器即可
用戶量大的策略(柔性服務策略)
- 前端處理95%的請求直接返回已經售光(前端隨機數,矩陣,離散等概率算法)
- 全局計數處理
- 降級跳過非關鍵邏輯
- 中間錯誤異步修復
- 業務流程上可以通過:搶購預約碼
有損服務的策略(列表頁)
第一種策略
列表頁分爲三塊,同時發起三個異步請求後端進行處理
第二種策略
A:搜索篩選項時,比如搜索海淀-知春路的帖子,只出海澱的帖子(維度高一些)
B:第三塊是廣告頁可以選擇不展示
C:列表頁中的數據可以繼續簡化(簡化埋點,日誌,廣告等業務數據)
D:篩選項可以進行15分鐘一次的緩存刷新