lettuce堆外內存溢出bug
當進行壓力測試時后期后出現堆外內存溢出OutOfDirectMemoryError
產生原因:
1)、springboot2.0以后默認使用lettuce作為操作redis的客戶端,它使用netty進行網絡通信
2)、lettuce的bug導致netty堆外內存溢出。netty如果沒有指定堆外內存,默認使用Xms的值,可以使用-Dio.netty.maxDirectMemory進行設置
解決方案:
由於是lettuce的bug造成,不要直接使用-Dio.netty.maxDirectMemory去調大虛擬機堆外內存,治標不治本。
1)、升級lettuce客戶端。但是沒有解決的
2)、切換使用jedis
lettuce和jedis是操作redis的底層客戶端,RedisTemplate是再次封裝
1 2 3 <dependency> 4 <groupId>org.springframework.boot</groupId> 5 <artifactId>spring-boot-starter-data-redis</artifactId> 6 <exclusions> 7 <exclusion> 8 <groupId>io.lettuce</groupId> 9 <artifactId>lettuce-core</artifactId> 10 </exclusion> 11 </exclusions> 12 </dependency> 13 <dependency> 14 <groupId>redis.clients</groupId> 15 <artifactId>jedis</artifactId> 16 </dependency>
緩存:穿透、雪崩、擊穿
穿透
緩存穿透是指緩存和數據庫中都沒有的數據,而用戶不斷發起請求,如發起為id為“-1”的數據或id為特別大不存在的數據。這時的用戶很可能是攻擊者,攻擊會導致數據庫壓力過大。
解決方案
緩存空對象,MVC攔截器
雪崩
緩存雪崩是指在我們設置緩存時key采用了相同的過期時間,導致緩存在某一時刻同時失效,請求全部轉發到DB,DB瞬時壓力過重雪崩。
解決方案
規避雪崩:緩存數據的過期時間設置隨機,防止同一時間大量數據過期現象發生。
如果緩存數據庫是分布式部署,將熱點數據均勻分布在不同緩存數據庫中。
設置熱點數據永遠不過期。
出現雪崩:降級 熔斷
事前:盡量保證整個 redis 集群的高可用性,發現機器宕機盡快補上。選擇合適的內存淘汰策略。
事中:本地ehcache緩存 + hystrix限流&降級,避免MySQL崩掉
事后:利用 redis 持久化機制保存的數據盡快恢復緩存
擊穿
緩存擊穿 指 並發查同一條數據。緩存擊穿是指緩存中沒有但數據庫中有的數據(一般是緩存時間到期),這時由於並發用戶特別多,同時讀緩存沒讀到數據,又同時去數據庫去取數據,引起數據庫壓力瞬間增大,造成過大壓力
緩存雪崩是不同數據都過期了,很多數據都查不到從而查數據庫。
解決方案
設置熱點數據永遠不過期。
加互斥鎖:業界比較常用的做法,是使用mutex。簡單地來說,就是在緩存失效的時候(判斷拿出來的值為空),不是立即去load db去數據庫加載,而是先使用緩存工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一個mutex key,當操作返回成功時,再進行load db的操作並回設緩存;否則,就重試整個get緩存的方法。
擴展
如果是單機服務可以使用 synchronized(this), JUC(look)
鎖時序問題
之前的邏輯是查緩存沒有,然后取競爭鎖查數據庫,這樣就造成多次查數據庫。
解決方法:
競爭到鎖后,再次確認緩存中沒有,再去查數據庫。
鎖競爭模擬,多個服務同事操作同一個命令

復制微服務

分布式緩存
本地緩存問題:每個微服務都要有緩存服務、數據更新時只更新自己的緩存,造成緩存數據不一致
解決方案:分布式緩存,微服務共用 緩存中間件
分布式項目時,但本地鎖只能鎖住當前服務,需要分布式鎖
redis分布式鎖的原理:setnx,同一時刻只能設置成功一個
設置好了鎖,玩意服務出現宕機,沒有執行刪除鎖邏輯,這就造成了死鎖
解決:設置過期時間
業務還沒執行完鎖就過期了,別人拿到鎖,自己執行完去刪了別人的鎖
解決:鎖續期(redisson有看門狗),。刪鎖的時候明確是自己的鎖。如uuid
判斷uuid對了,但是將要刪除的時候鎖過期了,別人設置了新值,那刪除了別人的鎖
解決:刪除鎖必須保證原子性(保證判斷和刪鎖是原子的)。使用redis+Lua腳本完成,腳本是原子的