- 簡單工廠模式UML
- 概要
- 日誌框架歷史?
- 門面日誌框架 VS 具體實現日誌框架?
- SLF4J應用之設計模式?
- 遺留問題 : 各第三方框架採用的日製框架不同 , 如何統一日誌框架?
- Spring Boot日誌框架配置?
- 門面日誌框架
為了讓接口與具體實現抽離,因此誕生了門面日誌框架,常見框架如下
- Jarkarta Common Logging
- 運行時動態綁定Log實現類
- 缺點 : 多ClassLoader導致的問題 , 2014年已停止維護
- SLF4J(Simple Logging Facade for Java)
- 編譯時綁定Log實現類
- 實現了項目與具體日誌框架解耦.統一了各種日誌框架的使用方法,降低重複的學習成本
- spring boot專案預設使用logback包,欲更換可進行排除
- spring boot <=1.3 版本支援log4j
- spring boot >=1.4 版本支援log4j2
- 執行slf4j程式與結果
slf4j因找不到具體日誌框架實作類,拋出錯誤
- org/slf4j/impl/StaticLoggerBinder.class會尋找所有SLF4J的實現類
- 實現org/slf4j/impl/StaticLoggerBinder.class與log4j
- 實現org/slf4j/impl/StaticLoggerBinder.class與log4j2
- 如果上述兩項接引用JAR包 , 系統會提示找到多個實現類、使用了哪一個JAR包
- SLF4J應用之設計模式?
- Facade模式
- 外部與一系统的通信必須通過一個統一的入口進行,使得子系统更易于使用
- 用在自定義utils?
- Netflix Zuul? Spring Cloud Getwate?
- Netflix 的閘道方案使用 Zuul,雖然最新版本是 Zuul 2,不過 Spring Cloud 整合的版本僅 Zuul 1,這中間的插曲是 Zuul 2 原本預計在 2016 年底左右發佈,然而卻拖到了 2018 年 4 月,在這段期間,Spring 就自己搞了個 Spring Cloud Gateway,不打算整合 Zuul 2 了。
- SLF4J提共了統一接口 , 使用者無需關心具體實現方式
- Adapter模式
- 如同轉接頭 , 將兩者功能能配合在一起使用
- 例如 , 因為在Log4J的發展歷史較早 , Log4J1並未考慮到後來出現的SLF4J , 因此SLF4J提共許多Adapter包 , 能夠與Log4J配合
- 遺留問題 : 各第三方框架採用的日誌框架不同 , 如何統一日誌框架?
- Spring Boot預設日誌配置?
- 僅載入 spring-boot-starter的情形下
- 使用 IntellJ 在pom.xml上按下右鍵開啟 Diamgram->Dependcy
- 可察看到 , 官方預設使用了sslf4j+logback作為日誌框架實現
- 還加入其他日誌框架橋接包, 替換成slf4j , 依情形僅需排除第三庫依賴的日誌依賴,spring boot自動幫你配置起來
- 調優目標
- GC時間足夠小
- GC次數足夠少
- Full GC週期足夠長
- Full GC次數少
- 移轉到老年代的對象少
- 調優結果
- 代碼減少使用全局變量和大對象
- 調整新生代大小
- 調整老年大大小
- 選擇合適的GC收集器
- 調優步驟
- 監控GC狀態
- 生成Dump文件
- 分析Dump文件
- 調整參數
- 監控GC狀態
- 開啟GC日誌(3選1)
# -XX:+PrintGCDetails
# -XX:+PrintGCTimeStamps
# -XX:+PrintGCDateStamps
- 存放GC日誌檔
# -Xloggc:/gc.log
- 需注意之狀態
- Minor時間超過50ms
- Minor時間10秒內一次
- Full GC時間超過1秒
- Full GC時間10分鐘內一次
- Full GC無效果
- 生成Dump文件
- 開啟OOM Dump文件
# -XX:+HeapDumpOnOutOfMemoryError
- 存放Dump文件 *.hprof
# -XX:HeapDumpPath=D:\
- 分析Dump文件 *.hprof
- 中文開啟 .....jdk/bin/jvisualvm.exe
# jvisualvm --locale zh:CN
- D:\>Java\jdk1.8.0_241\bin\jvisualvm.exe --locale zh:CN
- 調整參數
- 其他參數
- 減少GC次數
- -Xmx = -Xms
- -XX:newSize = -XX:MaxNewSize
- 提高閥值 -XX:MaxTenuringThreshold
- 調整Old區
- 觀察Old區之峰值 , 適當調高Young區 , 但會增加mior gc時間 , 關鍵字NewRatio
- 硬體較好的設備可在Old區使用並行收集算法
# -XX:+UseParallelOldPC
- 調整Stack
- 每個線呈默認開啟 1M stack , 內存不變下可增加線呈數
- 重複演練
- 其他
- 吞吐量優先的並行收集器與響應時間優先的併發收集器選擇
- 參考網址
- 何謂GC回收?
- 分代收集算法
- 特性
- GC次數較頻繁收集於Heap Young區
- GC次數較少收集於Heap Old區
- 基本上不動的收集於Perm區
- Heap Young
- 複製算法( Copying )
- 當Eden內存滿時 , Minor GC清空Eden區 , 將 From區與Eden區存放於To區
- From區與To區的內存不斷進行複製、移動、整理
- 優點 : 內存碎片減少、效率高
- 缺點 : 需要2倍內存空間、
- Heap Old
- 標記清除( Mark-Swap )
- 第一次掃描進行標記
- 第二次掃描進行清除
- 優點 : 不浪費內存空間(不用2倍內存)
- 缺點 : 掃描兩次、產生內存碎片
- 標記壓縮( Mark-Compact )
- 第一次掃描標記
- 第二次掃描移動(壓縮)
- 優點 : 無內存碎片
- 缺點 : 掃描兩次
- 標記清除壓縮( Mark-Swap-Compact )
- Mark-Swap + Mark-Compact
- 多次 Mark-Swap GC之後才做Mark-Compact
- 優點 : 減少移動成本
- 3種垃圾回收方式
- 參考網址
- ClassLoader構造
- 沙箱安全機制
- 類別保護機制 , 呼叫類別優先從上層級別開始 , 因此開發人員無法複寫例如 java.lang.String類別
- Stack構造
- java.lang.StackOverFlowError
- Heap構造
- OOM : Heap
- 當內存不足時 , JVM連續發生GC時
- 每次回收小於2%
- 資料來源
- 基於Redis資料庫實現分佈鎖
- 基於分佈式環境才有分佈鎖之問題
- 需要以原子操作
- 無法使用JVM級別的鎖
- 將併發進行串行化(多路復用)操作,缺點就是無法支持高併發
- 可使用ZK鎖以決定Redis主從資料庫的資料一致性
- 情境如下
- 庫存數量10
- 下單後庫存-1
- 使用jmeter壓測
- 單例模式 (僅一個tomcat處理)
- 演變1
- 邏輯 : 單純將庫存-1
- 缺點 : 扣減錯誤 , 單機環境也可使用 sychronize鎖解決 , 但分布式環境併發仍會扣減錯誤
- 演變2
- 邏輯 : 使用redis setnx() or incr() 決定線呈是否取得鎖=1 , 結束後還原=0
- 缺點 : 部分線程雖優先順序較高 , 但無法取得鎖 ,造成後續扣減無法完成
- 缺點 : 如果程式執行發生異常或web應用掛機 , 鎖無法取消
- 演變3
- 邏輯 : 將鎖設置超時時間
- 缺點 : 後面線程將前面線程的鎖解除
- 缺點 : 超時時間不好預估
- 演變4
- 邏輯 : 使用redission框架 , 設置後台子線程 , 監測主線程是否還在執行, 如果還在執行則延遲超時時間 , 其他線程沒有取得鎖則循環嘗試加鎖
- 缺點 : 自旋處理有其缺點及適用場景
- Redission框架
- 可立即使用在分布式鎖環境
- 悲觀鎖 : 僅有取得鎖的線程可持續加鎖 , 其他線程要取得鎖必須等待 , 有性能問題
- 參考網址
- 多執行續演變
- <= JDK 1.4
- = JDK 1.5
- Thread Pool
- AIO
- Excutor
- Concurrent包
- 創建執行續的4種方式
- Thread
- Runnable
- Callable
- 可以有返回值 , 由FutureTask支持接收結果 , get()->阻塞
- ThreadPool
- 如果沒有執行shutdown() , 執行續會持續進行
- 多執行續的 可見性、原子性、有序性問題
- 可見性 : 基於Java內存模型 , 每一個線程皆會從主存存取共用變數值至工作內存中進行運算 , 導致A線程已修改數據,B線程仍使用舊資料進行運算 , 因此有 Volatile修飾字的解決辦法
- 原子性 : 多個線程存取同一共用變數 , 同時進行"修改"所導致的問題 (Concurrent包)
- 有序性 : JVM因考量效能 , 在解析代碼會將沒有順序關係的變數進行順序調度 , 導致非預期結果
- Volatile 參考
- 保證共享(主)內存刷新
- 符合有序性、可見性
- 不符合原子性
- Concurrent包
- 用於處理多執行續的
- 1.8之後符合CAS(Compare&Swap)演算法(原子性) , 使用native method硬體對併發的支持
- CAS原理
- 內存值V
- 預估值A
- 更新值B
- If V==A , V=B
- 屬於一種樂觀鎖機制
- 含原子操作用的Atomic api
- 常見之Class , 介於Collection之非執行續安全類別~執行續安全類別之間
- ConcurrentHashMap
- ConcurrentSkipListMap
- ConcurrentSkipListSet
- CopyOnWriteArrayList
- CopyOnWriteArraySet
- 常見多執行續"鎖"之種類介紹
- 悲觀鎖
- 當對象被線程鎖上時,其餘線程必須等待鎖釋放才可存取
- 例如 synchronize
- 缺點沒控制好性能通常較差
- 樂觀鎖
- 當未完成操作時 , 進行重試
- 例如 CAS進行硬件級別鎖
- 缺點ABA問題 , 循環開銷大 , 一次只能保證一個共享變數(建議使用synchronize)
- 閉鎖操作
- CountDownLatch用於等待多線程操作完成
- 當計數器=0時代表開鎖
- 同步鎖
- synchronize區塊(隱式鎖)
- synchronize方法(隱式鎖)
- Lock(顯示鎖、樂觀鎖)
- 使用lock() 、 unlock()定義同步區塊
- 搭配condition生成await()、signal()、signalAll()
- Object原生的wait()如同await()建議放在while回圈內,防止虛假喚醒
- 補充
- synchronize屬於對象鎖 , 影響單一對象 , 如果另外生成對象則不影響
- static synchronize屬於類別鎖 , 影響全部對象
- synchronize與static synchronize兩者為獨立運行 , 各別控制運行
- 讀寫鎖
- 寫寫/讀寫兩種線程必須互斥 , 讀寫分離
- 一個 readLock() , 一個 WriteLock()
- Fork/Join框架
- 開啟慢查詢日誌 , 觀察一天或重現事故
- Explain + 慢查詢SQL
- Show Profile分析SQL生命週期
- DB參數優化
- 慢查詢日誌
- 使用慢查詢日誌 , 紀錄查詢效能差的SQL
- 當查詢時間超過long_query_time時寫入日誌,默認時間為10秒
- 開啟慢查詢日誌 , 設置後須重新連線DB
- Explain + 慢查詢SQL
- 使用Explain查看執行計畫 , 優化SQL
- SQL優化策略 (Index索引為其重點)
- 查詢執行計畫 : explain select ............最重要之4個欄位
- Id : 執行順序 , id越大優先執行 , id值相等則上方列優先
- type : 查詢等級System>const>eq_ref>ref>range>index>all
- rows : 預估要查詢的列數 , 越少越好
- extra : 其他index>filesort>temporary
- SQL優化策略
- Index優化策略
- select和where欄位皆可使用
- MySQL CRUD皆會做查詢的動作, 因此Index索引決定效能
- MyIsam引擎將資料與索引拆分成兩份檔案InnoDB為同一份檔案查詢效能較好
- 建議PK使用數值或自動產生流水號查詢效能較文字高
- 建議一定要加PK , 否則默認由DB自己判斷生成RowId
- MySQL 預設使用 B+Tree資料結構儲存索引
- 根據官方分析過,預設高度為3
- 完成資料data存在於最後一層索引上 , 與其他資料結構僅儲存磁碟位置不同
- Mysql另外有一種Hash資料結構, 較適合等值where條件
- 組合索引必須依序讀取/設置
- range索引(>= , > , < , <=)導致後續的索引失效 , 故可將此欄位放置在最後面
- 欄位不使用函數、計算
- 當使用left join時 , index加在右表 , 反之亦然
- 少使用select * , 使用覆蓋索引(欄位順序個數跟Index完全相同)效能佳
- 少用 OR
- Varchar必用單引號 , 以免索引失效
- 不使用 >< , != , 以免索引失效
- 不使用 is null , is not null , 以免索引失效, 使用 ''代替null欄位
- Like必須使用 'X%'以免索引失效 , 否則可用覆蓋索引彌補
- 查詢優化策略
- join buffer大小可以視情況調整
- 小表(A)驅動大表(B)查詢 , B in (A) 或 A exist (B)
- Order By優化策略
- 可搭配Index左前戳開頭規則 , 建立組合索引
- 不可使用 select *
- 所有排序欄位必須一致遞升或遞減
- sort_buffer_size不足會導致多次I/O、臨時表多路合併 (這是每個進程都有一份)
- max_length_for_sort_data不足會導致臨時表與多路合併
- 當max_length_for_sort_data設置過大會導致sort_buffer_size不足
- 當查詢筆數<max_length_for_sort_data且排序欄位並非text|blob , 使用單路排序
- Group By優化策略
- 實質上是先排序後分組
- 與Order By索引規則相同
- 當無法使用索引 , 則增加sort_buffer_size和max_length_for_sort_data
- Show Profile分析SQL生命週期
- 分析SQL執行細節和生命週期 , 查出問題點
- 開啟profile功能
- 診斷方式
- Status欄位不得出現之訊息 , 將嚴重影響效能