java技術點整理
Dubbo: 2.7.X
1.Dubbo配置優先順序: jvm -> xml -> properties
2.xml中配置覆蓋優先順序:
a. 方法級優先,介面級次之,全域性配置再次之
b. 如果級別一樣,則消費方優先,提供方次之
3.重要配置介紹
a. 超時時間: 預設1秒
b. 重試次數: 預設2次,不包含第一次呼叫,冪等性操作才配置(查詢,刪除,更新)
c. 多版本: version, 實現灰度釋出
d. 本地存根: stub, 呼叫服務之前,做一些操作(引數校驗)
4.高可用
a. zookeeper宕機與dubbo直連
現象: zookeeper註冊中心宕機,還可以消費dubbo暴露的服務
原因: 註冊中心全部宕掉後,服務提供者和服務消費者仍能通過本地快取通訊
b. 負載均衡機制
隨機方式+權重(預設)
輪詢方式+權重
最少活躍數
一致性雜湊
c. 服務降級
遮蔽(force): return+null
容錯(fail): return+null
d. 叢集容錯: hystrix, sentinel
5.通訊方式: netty
6.架構設計
a.整體架構
config 配置層:對外配置介面,以 ServiceConfig, ReferenceConfig 為中心,可以直接初始化配置類,也可以通過 spring 解析配置生成配置類
proxy 服務代理層:服務介面透明代理,生成服務的客戶端 Stub 和伺服器端 Skeleton, 以 ServiceProxy 為中心,擴充套件介面為 ProxyFactory
registry 註冊中心層:封裝服務地址的註冊與發現,以服務 URL 為中心,擴充套件介面為 RegistryFactory, Registry, RegistryService
cluster 路由層:封裝多個提供者的路由及負載均衡,並橋接註冊中心,以 Invoker 為中心,擴充套件介面為 Cluster, Directory, Router, LoadBalance
monitor 監控層:RPC 呼叫次數和呼叫時間監控,以 Statistics 為中心,擴充套件介面為 MonitorFactory, Monitor, MonitorService
protocol 遠端呼叫層:封裝 RPC 呼叫,以 Invocation, Result 為中心,擴充套件介面為 Protocol, Invoker, Exporter
exchange 資訊交換層:封裝請求響應模式,同步轉非同步,以 Request, Response 為中心,擴充套件介面為 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
transport 網路傳輸層:抽象 mina 和 netty 為統一介面,以 Message 為中心,擴充套件介面為 Channel, Transporter, Client, Server, Codec
serialize 資料序列化層:可複用的一些工具,擴充套件介面為 Serialization, ObjectInput, ObjectOutput, ThreadPool
b.標籤解析
DubboNamespaceHandler--init(): 初始化對應的標籤class物件
DubboBeanDefinitionParser--parse(): 根據對應的beanClass做相應的處理
c.服務暴露
解析配置檔案
建立dubbo標籤解析器
解析dubbo標籤
serviceBean解析
容器建立完成,觸發ContextRefreshedEvent
暴露服務: export() -> doExport() -> doExportUrls() -> doExportUrlsFor1Protocol()
getInvoker()
protocol.export(wrapperInvoker)
openServer(url): new NettyServer
ProviderConsumerRegTable.registerProvider()
d.服務引用
ReferenceBean ---> FactoryBean.getObject() -> get() -> init()
createProxy()
refer(): 引用遠端服務
getClients(): 連接獲取客戶端 new NettyClient
doRefer(): 訂閱服務
ProviderConsumerRegTable.registerConsumer
返回invoker
e.服務呼叫
Proxy: ProxyFactory
Filter: mock,cache
Invoker: Cluster(failover,failfast)
LoadBalance: random
Filter: count, monitor
Invoker: Protocol(dubbo)
Client: Transporter(netty)
7.Dubbo中的Invoker概念瞭解嗎?
Invoker是Dubbo領域模型中非常重要的一個概念,是Dubbo對遠端呼叫的抽象,Invoker會遮蔽掉遠端呼叫的細節
8.Dubbo的SPI機制瞭解嗎? 如何擴充套件Dubbo中的預設實現
SPI機制被大量用在開源專案中,它可以幫助我們動態尋找服務/功能的實現,
原理:我們將介面的實現類放在配置檔案中,我們在程式執行過程中讀取配置檔案,通過反射載入實現類。這樣,我們可以在執行的時候,動態替換介面的實現類。
擴充套件:建立對應的實現類,將實現類的路徑寫入到resources目錄下的具體檔案中
9.Dubbo支援哪些序列化方式
JDK自帶的序列化,hessian2(預設), JSON, Kryo, FST, Protostuff, ProtoBuf
Spring5:
1.IOC
概念: 控制反轉,把物件建立和物件之間的呼叫過程,交給spring進行管理(為了降低耦合度)
實現:
BeanFactory: spring內部使用介面,載入配置檔案時,不建立物件,使用時才建立
ApplicationContext: BeanFactory的子介面,開發人員使用,載入配置檔案時,建立物件
Bean管理:
spring建立物件
spring注入屬性
bean的作用域: scope屬性值
singleton(單例,預設)
prototype(多例,getBean建立物件)
request(一次request 一個例項)
session(當前session內有效)
global Session(全域性http session有效)
bean的生命週期
1. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
2. bean例項化(建構函式)**********
3. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
4. InstantiationAwareBeanPostProcessor.postProcessProperties()
5. bean設定屬性值 **********
6. Aware相關介面設定(beanName, beanFactory, ApplicationContext)
7. BeanPostProcessor.postProcessBeforeInitialization()
8. InitializingBean.afterPropertiesSet()
9. init-method屬性配置的初始化方法 **********
10. BeanPostProcessor.postProcessAfterInitialization()
11. 返回bean給使用者,並存入快取池
12. DisposableBean.destroy()
13. 呼叫destroy-method屬性配置的銷燬方法 **********
自動裝配: autowire屬性值
1. no: 不進行自動裝配,顯示設定ref
2. byName: 通過引數名自動裝配
3. byType: 通過引數型別自動裝配
4. constructor: 類似於byType,需提供給構造器引數
5. autodetect: 先使用constructor來自動裝配,如果無法工作,則使用byType方式
建立物件註解
@Component
@Repository
@Service
@Contoller
屬性注入註解
@value: 普通型別
@Autowired
@Qualifier: 指定名稱
@Resource: 註解如果名字沒有配對成功,會按照型別進行注入
2.AOP(AspectJ)
常用術語
a. 連線點: 類中可以被增強的方法
b. 切入點: 實際被增強的方法
1. execution([許可權修飾符][返回型別][類全路徑][方法名稱]([引數列表]))
2. execution(* com.shizhuang.dupp.*(..))
3. @annotation(註解全路徑)
c. 通知: 實際增強的邏輯部分(前置,後置,環繞,異常,最終)
通知順序: 環繞通知前->前置通知->方法執行->環繞通知後->後置通知->最終通知
代理優先順序: @Order(1) 載入順序不受影響,隻影響程式的執行順序
d. 切面: 把通知應用到切入點的過程
JDK動態代理:
a. 實現InvocationHandler介面
b. Proxy.newProxyInstance
CGLIB動態代理
3.事務(底層使用AOP)
概念: 資料庫操作的基本單元,邏輯上一組操作(轉賬)
方式: 程式設計式事務管理,宣告式事務管理
註解:@Transactional
事務傳播行為:propagation
1. never:方法不應該執行在事務中,有則拋異常
2. required:有事務就在事務中執行,無則啟動新事務
3. required_new:必須啟動新事務,有則掛起
4. supports:有事務就在事務中執行,無則不在事務中執行
5. not _support:不在事務中執行,有則掛起
6. mandatory:必須執行在事務中,無則拋異常
7. nested:有事務就在事務的巢狀事務中執行,無則啟動新事務
事務隔離級別
髒讀:一個未提交事務讀取另一個未提交事務資料
不可重複讀:一個未提交事務讀取另一個已提交事務資料(update)
幻讀:一個未提交事務讀取另一個已提交事務資料(insert,delete)
1. 讀未提交
2. 讀已提交
3. 可重複讀
4. 序列化
4.spring中經典的9種設計模式
1.簡單工廠
BeanFactory
2.工廠方法
FactoryBean
3.單例模式
4.介面卡模式
HandlerAdatper
5.裝飾器模式
Wrapper,Decorator
6.代理模式
Aop底層
7.觀察者模式:Observable
spring的事件驅動模型
8.策略模式
Resource
9.模板方法模式
IOC初始化容器
10. 原型模式
原型bean的建立
5.SpringWebflux
a.非同步非阻塞
b.響應式程式設計(reactor):觀察者模式(Observer,Observable)
c.Reactor: 兩個核心類,實現Publisher
1.Mono: 實現釋出者,返回n個元素
2.Flux: 實現釋出者,返回0或者1個元素
3.資料訊號:元素值,錯誤訊號,完成訊號
d.核心控制器:DispatcherHandler 實現 WebHandler
HandlerMapping: 請求查詢到處理的方法
HandlerAdapter: 真正請求處理
HandlerResultHandler: 響應結果處理
e.重要介面:RouterFunction(路由處理)和HandlerFunction(函式處理)
面試官:”Spring是如何解決的迴圈依賴?“
答:Spring通過三級快取解決了迴圈依賴,其中一級快取為單例池(singletonObjects),二級快取為早期曝光物件earlySingletonObjects,三級快取為早期曝光物件工廠(singletonFactories)。當A、B兩個類發生迴圈引用時,在A完成例項化後,就使用例項化後的物件去建立一個物件工廠,並新增到三級快取中,如果A被AOP代理,那麼通過這個工廠獲取到的就是A代理後的物件,如果A沒有被AOP代理,那麼這個工廠獲取到的就是A例項化的物件。當A進行屬性注入時,會去建立B,同時B又依賴了A,所以建立B的同時又會去呼叫getBean(a)來獲取需要的依賴,此時的getBean(a)會從快取中獲取,第一步,先獲取到三級快取中的工廠;第二步,呼叫物件工廠的getObject方法來獲取到對應的物件,得到這個物件後將其注入到B中。緊接著B會走完它的生命週期流程,包括初始化、後置處理器等。當B建立完後,會將B再注入到A中,此時A再完成它的整個生命週期。至此,迴圈依賴結束!
面試官:”為什麼要使用三級快取呢?二級快取能解決迴圈依賴嗎?“
答:如果要使用二級快取解決迴圈依賴,意味著所有Bean在例項化後就要完成AOP代理,這樣違背了Spring設計的原則,Spring在設計之初就是通過AnnotationAwareAspectJAutoProxyCreator這個後置處理器來在Bean生命週期的最後一步來完成AOP代理,而不是在例項化後就立馬進行AOP代理。
Spring AOP和AspectJ AOP有什麼區別?
Spring AOP屬於執行時增強,而AspectJ是編譯時增強
Spring AOP基於代理, 而AspectJ基於位元組碼操作
當切面太多的話,最好選擇AspectJ, 會快很多
Spring管理事務的方式
程式設計式事務,在程式碼中硬編碼
宣告式事務,在配置檔案中配置
基於XML的宣告式事務
基於註解的宣告式事務
@Component和@Bean的區別是什麼?
作用物件不同:@Component註解作用於類,而@Bean註解作用於方法
@Component是自動裝配到Spring容器中,@Bean是在標有該註解的方法中定義產生這個bean
@Bean註解比@Component註解的自定義性更強
Nacos: 1.4.x
1.配置管理
四大特性
1.服務發現與服務健康檢查
2.動態配置管理
3.動態DNS服務
4.服務和元資料管理
常用概念
Namespace: 環境
Group: 專案
Data id: 工程
配置的優先順序
1.通過內部相關規則(應用名、副檔名)
2.通過ext-config[n]方式擴充套件,n的值越大,優先順序越高
3.通過shared-dataids支援多個Data Id的配置
2.服務發現
負載均衡
1.服務端負責均衡: nginx
2.客戶端負責均衡: ribbon
SpringCloud-Gateway
1.閘道器解決了什麼問題
統一接入
高效能、高併發
負載均衡、容災切換
流量控制
服務降級
熔斷
協議適配
前端(http)、後端(rpc)
長短連結支援
安全防護
黑名單
風控
2.閘道器應當具備的功能
效能:api高可用、負載均衡、容錯機制
安全:許可權身份驗證、脫敏、流量清洗、後端簽名、黑名單
日誌:全鏈路
快取:資料快取
監控:記錄請求響應資料、api耗時分析、效能監控
限流:流量控制、錯峰流控
灰度:線上灰度部署
路由:動態路由規劃
3.Gateway工作原理
客戶端向Spring Cloud Gateway發出請求,再由閘道器處理程式Gateway Handler Mapping
對映確定與請求相匹配的路由,將其傳送到閘道器Web處理程式Gateway Web Handler,該處理程式通過
指定的過濾器鏈將請求傳送到我們實際的服務執行業務邏輯,然後返回。pre過濾器(之前)、post過濾器(返回)
4.路由規則
Path: 請求路徑
Query: 請求引數,值可以使用正則匹配
Method: 請求方式
Datetime: 指定時間之前,之後,之間
RemoteAddr: 遠端地址
Header: 指定請求頭
動態獲取URI: lb://根據服務名稱從註冊中心獲取服務請求地址
服務名稱轉發:
discovery - locator
enabled(true): 開啟基於服務發現的路由規則
lower-case-service-id(true): 是否將服務名稱轉小寫
5.過濾器
Path路徑過濾器: 實現URL重寫,新增指定字首,剝離路徑個數,路徑模板引數
引數過濾器
狀態過濾器
全域性過濾器(統一鑑權)
6.閘道器限流
計數器演算法: 臨界問題,資源浪費
漏桶演算法: 佇列機制
令牌桶演算法: 恆定的速度生成令牌(redis+lua)
限流、降級、熔斷
Sentinel 1.8.x
1.簡介
Sentinel的核心骨架是ProcessorSlotChain,其將不同的Slot按照順序串在一起,
系統會為每個資源建立一套SlotChain。
2.slot介紹
NodeSelectorSlot: 負責收集資源的路徑,並將這些資源的呼叫路徑以樹狀結構儲存起來
ClusterBuilderSlot: 用於儲存資源的統計資訊和呼叫者資訊
StatisticSlot: 用於記錄、統計不同維度的runtime指標監控資訊
3.Node間的關係
Node: 用於完成資料統計的介面
StatisticNode: 統計節點,是Node介面的實現類,用於完成資料統計
EntranceNode: 入口節點,一個Context會有一個,用於統計當前Context的總體流量資料
DefaultNode: 預設節點,用於統計一個資源在當前Context中的流量資料
ClusterNode: 叢集節點,用於統計一個資源在所有Context中的總體流量資料
4.原始碼分析流程
1.建立資源操作物件
SentinelResourceAspect: 切面為SentinelResource註解,環繞通知
entryWithPriority: 資源物件,統計值(預設1),是否優先順序
從ThreadLocal中獲取context, 一個執行緒繫結一個context
若context是NullContext型別,即訪問請求的數量已經超出閾值,返回無需校驗的資源操作物件
若當前執行緒沒有context,建立一個context("sentinel_default_context")放入ThreadLocal
如全域性開關是關閉的,返回無需校驗的資源操作物件
2.建立context
從ThreadLocal中再獲取一次
ThreadLocal中不存在,雙重檢測從快取(context名稱,EntranceNode)中獲取
快取超過閾值,返回NULL_CONTEXT
快取不超過閾值,建立EntranceNode,並加到root和快取中
3.獲取chain(單向連結串列)
雙重檢測從快取中獲取chain,沒有則新建
沒有SlotChainBuilder則通過Spi方式建立
通過Spi方式填充ProcessorSlot
4.slot執行流程
NodeSelectorSlot: 雙重檢測獲取或者建立DefaultNode,並新增到呼叫樹中
StatisticSlot:
呼叫SlotChain中後續的所有slot(會拋異常)
通過則增加執行緒數和通過的請求數
DegradeSlot:
異常熔斷器,響應時間熔斷器
如果熔斷器關閉,直接通過
如果開啟,時間大於下個視窗開始時間且是CAS半開啟狀態成功,再次判斷
5.時間視窗
固定時間視窗:跨時間視窗的長度大於閾值
滑動時間視窗:重複計算問題(新增固定樣本視窗)
視窗實現:ArrayMetric - LeapArray<MetricBucket> - AtomicReferenceArray<WindowWrap<T>>
WindowWrap代表樣本視窗物件,MetricBucket是樣本視窗資料,MetricEvent列舉6種類型資料通過陣列儲存
獲取視窗: 根據樣本視窗id 和 視窗起始時間獲取樣本視窗(新建,當前,清空複用)
6.降級、熔斷、限流
限流:控制某段時間內請求總量(計數器,滑動視窗,漏桶,令牌桶)
熔斷:一般是指依賴的外部接口出現故障的情況,斷絕和外部介面的關係
降級:保證核心功能的可用性,選擇性的降低一些功能的可用性,或者直接關閉該功能
Seata分散式事務(讀未提交)
CAP理論: Consistency(一致性), Availability(可用性), Partition tolerance(分割槽容錯性)
CA: 單點的傳統關係型資料庫mysql、oracle
CP: 保證分割槽容錯和一致性zk、redis、mongoDB、Hbase
AP: 保證分割槽容錯和可用性CoachDB, 秒殺
BASE理論
BA: 基本可用
S: 柔性狀態,執行資料同步存在延遲
E: 最終一致性
二段提交協議
投票階段: undo和redo日誌寫入, 不提交事務
提交階段: 提交事務操作,成功返回ack
三段提交協議
Can-Commit: 是否可以執行
Pre-Commit: undo和redo日誌寫入, 不提交事務
Do-Commit: 提交事務操作,成功返回ack
第三階段,如果協調者無法通訊,參與者也會提交事務
分散式事務解決方案
TCC: 事務補償(2pc)
全域性訊息
基於可靠訊息服務的分散式事務
最大努力通知
Seata術語
TC: 事務協調者,維護全域性和分支事務的狀態,驅動全域性事務提交或回滾
TM: 事務管理器,定義全域性事務範圍,開始、提交或回滾全域性事務
RM: 資源管理器,管理分支事務處理的資源,驅動分支事務提交或回滾
AT模式
TC相關的表解析
global_table: 全域性事務,每當有一個全域性事務發起後,就會在該表中記錄全域性事務的ID
branch_table: 分支事務,記錄每一個分支事務的ID,分支事務操作的資料庫等資訊
lock_table: 全域性鎖
for update操作在未獲取到資料的時候,mysql不進行鎖
獲取到資料的時候,進行對約束欄位進行判斷,存在有索引的欄位則進行行鎖,否則進行表鎖
當使用< > like等關鍵字時,進行for update操作時,mysql進行的是表鎖
原始碼分析:spi方式裝配,@GlobalTransactional
入口: GlobalTransactionScanner, 繼承AbstractAutoProxyCreator, 實現InitializingBean
重寫父類wrapIfNecessary()
建立GlobalTransactionalInterceptor
物件執行invoke()
執行handleGlobalTransaction()
TransactionalTemplate.execute()
開啟事務:底層通過netty呼叫seata客戶端開啟事務,並通過session方式,獲取xid,最終通過jdbc方式寫入到資料庫
執行業務:寫入undo_log日誌,beforeImg, afterImg
提交事務
RocketMQ
1.MQ的用途:限流削峰,非同步解耦,資料收集
2.MQ常見協議:JMQ, STOMP,AMQP,MQTT
3.路由發現模型:push模型,pull模型,Long Polling模型
4.topic的建立模式: 叢集模式,broker模式
5.讀/寫佇列的目的: 方便topic的Queue的縮容
6.broker叢集模式:Master配置RAID10磁碟陣列,然後再為其配置一個slave
7.磁碟陣列RAID
技術:映象,資料條帶(自動將I/O操作負載均衡到多個物理磁碟上的技術),資料校驗
目的:高效能,高可靠,容錯能力,擴充套件性
分類:軟RAID(功能有作業系統和CPU來完成), 硬RAID(控制處理晶片,I/O處理晶片,陣列緩衝)和混合RAID(有控制處理晶片)
等級:RAID10(先做條帶,再做映象,容錯率更高),RAID01(先做映象,再做條帶)
8.JBOD: 磁碟簇/磁碟櫃,表示一個沒有控制軟體提供協調控制的磁碟集合
9.配置檔案引數
brokerClusterName: 整個broker叢集的名稱
brokerName: master-slave叢集的名稱
brokerId:master的brokerId為0
deleteWhen: 刪除過期檔案的時刻
fileReservedTime: 為發生更新的訊息儲存檔案的保留時長
brokerRole: 複製策略
flushDiskType: 刷盤策略
namesrvAddr: Name Server的地址
10.重要概念
路由表:是一個Map,key是topic名稱,value是一個QueueData例項(一個broker的所有該topic的queue)列表
broker列表:是一個map,key是brokerName, value是BrokerData(master-slave叢集)
11.Queue選擇演算法:針對無序訊息,輪詢演算法,最小投遞延遲演算法
12.store目錄簡介
abort: 該檔案在broker啟動後會自動建立,正常關閉broker,該檔案會自動消失
checkpoint: 儲存著commitlog,consumequeue,index檔案的最後刷盤時間戳
commitlog: mappedFile檔案(小於等於1G)
a.訊息在broker中存放時,並沒有按照topic進行分類存放
b.訊息單元中包含queue相關屬性
config: 存放著broker執行期間的一些配置資料
consumequeue: consumequeue檔案是commitlog的索引檔案
a.每個檔案包含30W個索引條目
b.索引條目: commitlog Offset, 訊息長度,訊息Tag的hashCode值
c.三個屬性固定20個位元組,檔案大小30W*20位元組
index:根據key進行訊息查詢功能(時間戳命名)
a.索引條目
1.indexHeader(40位元組,第一條和最後一條訊息儲存時間,在commitlog中的偏移量,已填充index的slot數量,索引個數: 2000W)
2.slot槽(500W)
3.indexes索引資料
b.index索引單元(20個位元組)
1.keyHash
2.phyOffset
3.timeDiff
4.preIndexNo
lock: 執行期間使用到的全域性資源鎖
13.效能提升:對檔案的讀寫操作是通過mmap零拷貝,資料是順序存放的(引入了PageCache的預讀取機制)
14.Rebalance機制
目的:提升訊息的並行消費能力
危害:消費暫停,重複消費,消費突刺
過程:每個consumer例項根據queue分配演算法,自主完成
TopicConfigManager: key是topic名稱,value是topicConfig(topic中所有Queue的資料)
ConsumerManager: key是Consumer Group Id, value是ConsumerGroupId(Group中所有的Consumer例項資料)
ConsumerOffsetManager: key為Topic@Group的組合,value是Map(key:QueueId,value: offset)
15.Queue分配演算法
a.平均分配策略
b.環形平均策略
c.一致性hash策略
d.同機房策略
16.重試佇列:key是%RETRY%開頭的ConsumerOffsetManager
17.訊息的清理: 預設過期時間72小時
a.檔案過期,凌晨4點清理
b.檔案過期,磁碟空間佔有率75%
c.最老的檔案,磁碟空間佔有率85%
d.拒絕訊息寫入, 磁碟空間佔有率90%
18.延時訊息:訊息寫入到broker後,在指定的時長後才可被消費的訊息
a.如果有延遲等級
b.修改訊息的topic為SCHEDULE_TOPIC_XXXX
c.根據等級delayLevel建立對應的queueId目錄與consumequeue檔案
d.索引單元,訊息Tag的hashCode值修改為訊息的投遞時間(儲存時間+延時時間)
e.queue中的訊息是按照投遞時間排序的
f.broker內部有個延遲訊息服務類ScheuleMessageService,會消費修改訊息的topic為SCHEDULE_TOPIC_XXXX中的訊息
g.將原來的延遲等級設定為0,再次投遞到目標Topic中
19.事務訊息(XA模式)
半事務訊息:不能被消費者看到
三劍客:TC(Broker), TM(Producer), RM(Broker和Producer)
不支援延時訊息
要做好冪等性檢查
20.訊息過濾:Tag過濾,SQL過濾(預設關閉)
21.訊息重試:順序訊息沒有重試機制
預設重試次數:16(2個小時)
處理:通過延時訊息實現
消費:消費者會預設訂閱重試佇列
22.死信佇列:重試失敗的訊息
Topic:%DLQ%consumerGroup@consumerGroup
Netty:4.1.x
1.介紹
a.netty是由JBOSS提供的一個java開源框架
b.netty是一個非同步的,基於事件驅動的網路應用框架
c.netty主要針對在TCP協議下,面向Clients端的高併發應用
d.netty本質是一個NIO框架
2.I/O模型:
a.BIO: 同步並阻塞
b.NIO: 同步非阻塞(channel,buffer,selector)
c.AIO: 非同步非阻塞
3.buffer屬性:mark, position, limit, capacity
4.channel: FileChannel, ServerSocketChannel, SocketChannel, DatagramChannel(用於UDP的資料讀寫)
5.MappedByteBuffer: DirectByteBuffer是它的子類,可讓檔案直接在堆外記憶體修改,作業系統無需拷貝一次
6.Selector:socketChannel註冊後返回SelectionKey
監聽方法
a.Selector.select() 阻塞
b.Selector.select(1000) 阻塞1000毫秒
c.Selector.wakeUp 喚醒Selector
d.Selector.selectNow 不阻塞
事件分類
a.OP_ACCEPT 16
b.OP_CONNECT 8
c.OP_WRITE 4
d.OP_READ 1
7.零拷貝: DMA(直接記憶體訪問)-> SG-DMA
早期I/O操作,記憶體與磁碟的資料傳輸工作都是由CPU完成的,而此時CPU不能執行其他任務
mmap(記憶體對映)+write:cpu把核心緩衝區的資料拷貝到socket緩衝區,4次上下文切換
sendFile:2次上下文呼叫,3次資料copy
pageCache: 快取最近被訪問的資料,預讀功能
傳輸大檔案:
非同步IO+直接IO
不能使用零拷貝:由於PageCache被大檔案佔據,導致熱點小檔案無法利用到PageCache
減少了兩次上下文切換和資料拷貝次數
8.Reactor模式:
reactor: 監聽事件,分發
handler: 處理事件
9.Netty工作原理
1.兩組執行緒池
BossGroup: 負責接收客戶端的連線
WorkerGroup: 負責網路的讀寫
2.兩組執行緒池型別都是NioEventLoopGroup
3.NioEventLoopGroup: 事件迴圈組,事件迴圈是NioEventLoop(執行緒)
4.BossGroup的NioEventLoop
輪詢accept事件
處理事件,與client建立連線
生成NioSocketChannel並註冊到WorkerGroup的NioEventLoop上的selector
處理任務佇列的任務
5.WorkerGroup的NioEventLoop
輪詢read,write事件
處理i/o事件
處理任務佇列的任務
6.每個Worker NioEventLoop處理業務時,會使用pipeline(管道),管道維護了很多處理器(handler)和 channel
10.NioEventLoop的taskQueue作用,用來非同步處理耗時比較久的任務, scheduledTaskQueue用來處理定時任務
11.ChannelFuture(非同步模型)
12.ChannelPipeline維護的雙向連結串列的元素是ChannelHandlerContext(裡面包含具體handler)
13.Unpooled: 操作緩衝區(Netty的資料容器)的工具類
copiedBuffer: 返回一個ByteBuf物件
ByteBuf: 不需要使用flip進行反轉(維護了 readerIndex和writerIndex)
14.IdleStateHandler: netty提供的處理空閒狀態的處理器
readerIdleTime: 多長時間沒有讀,傳送一個心跳檢測
WriterIdleTime: 多長時間沒有寫,傳送一個心跳檢測
allIdleTime: 多長時間沒有讀寫,傳送一個心跳檢測
15.Handler類中的userEventTriggered()方法可以接收上一個handler傳遞過來的事件
16.Protobuf: Google釋出的開源專案
結構化資料儲存
結構化資料序列化
跨平臺,跨語言
使用message管理資料
17. MessageToByteEncoder: 編碼器
編碼前會對型別校驗: acceptOutBoundMessage(msg), 不通過則直接傳送下個節點
18.tcp粘包拆包解決:自定義協議+編解碼器
執行緒池相關
1.只要建立的匯流排程數 >= maximumPoolSize 的時候,執行緒池就不會繼續執行任務了而會去執行拒絕策略的邏輯
2.執行緒池執行狀態-runState
RUNNING:接收新任務,並且也能處理阻塞佇列中的任務。
SHUTDOWN:不接收新任務,但是卻可以繼續處理阻塞佇列中的任務。
STOP:不接收新任務,同時也不處理佇列任務,並且中斷正在進行的任務。
TIDYING:所有任務都已終止,workercount(有效執行緒數)為0,執行緒轉向 TIDYING 狀態將會執行 terminated() 鉤子方法
TERMINATED:terminated() 方法呼叫完成後變成此狀態。
3.一個變數維護兩個值:執行狀態(runState)和執行緒數量 (workerCount)
高3位代表執行狀態(runState ),而低29位代表工作執行緒數(workerCount)
4.執行緒池整體流程
a.任務的非空校驗
b.核心執行緒數校驗
c.執行緒池狀態校驗(2次),新增佇列,池中沒有執行緒,建立一個新的執行緒(不傳任務)
d.佇列滿了,建立新的執行緒,失敗則執行拒絕策略
5.addWorker(Runnable firstTask, boolean core)流程
a.最外層for迴圈是不斷校驗當前的執行緒池狀態是否能接受新任務
b.檢查工作執行緒數,CAS增加執行緒數成功跳出迴圈(break retry;), 否則繼續判斷執行緒池狀態
c.建立Worker, 加鎖判斷執行緒池狀態, 將 worker 例項新增進執行緒池,修改largestPoolSize(出現過的最大執行緒數)
d.執行緒新增成功,執行start,新增失敗,執行緒池移除worker例項,CAS將工作執行緒數減1
6.Worker類詳情:ThreadPoolExecutor的一個內部類,繼承AQS(實現獨佔鎖), 實現Runnable
a.firstTask不為空立即執行任務,為空則去執行佇列中的任務(while條件判斷)
b.runWorker(Worker w)方法邏輯
1.allowCoreThreadTimeOut 為true允許核心執行緒關閉
2.獲取任務-getTask, 如果允許核心執行緒關閉,通過poll超時拉取, 否則通過take阻塞拉取
設計模式:
1.設計模式的七大原則
a.開閉原則:對擴充套件開放,對修改關閉
b.里氏替換原則: 所有引用基類的地方必須能透明地使用其子類的物件
c.依賴倒置原則: 上層模組依賴抽象, 細節依賴抽象
d.介面隔離原則: 客戶端不應該依賴它不需要的介面
e.迪米特法則(最少知道原則):只與你的直接朋友交談,不跟“陌生人”說話。
f.單一職責原則: 一個類應該只負責一項職責
g.合成複用原則: 儘量使用物件組合/聚合,而不是繼承關係達到軟體複用的目的
2.常用的設計模式
a.單例模式:餓漢式,懶漢式,雙重校驗,靜態內部類,列舉
JDK: Runtime類(餓漢式)
b.工廠模式
簡單工廠:工廠類直接建立物件(JDK, Calendar類)
工廠方法:工廠類抽象建立物件方法,工廠子類實現建立邏輯
c.抽象工廠模式
區別:工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個
d.原型模式
實現Cloneable介面
預設clone()方法(淺拷貝)
深拷貝:重寫clone()方法,序列化(輸出,輸入流)
e.建造者模式
Product: 最終要生成的物件
Builder: 構建者的抽象基類
ConcreteBuilder: Builder的實現類
Director: 決定如何構建最終產品的演算法(建構函式傳入builder的實現類物件)
f.介面卡模式(SpringMVC中的HandlerAdapter):講一個類的介面轉換成客戶希望的另外一個介面
類介面卡:Java是單繼承機制,要求適配物件必須是介面
物件介面卡:介面卡聚合被適配物件
介面介面卡:設計一個抽象類實現介面,空方法, 抽象類的子類可有選擇覆蓋實現需求
g.裝飾者模式:動態的將新功能附加到物件上(IO原始碼 FilterInputStream)
被裝飾者和裝飾者基類都實現了ICoffee介面
裝飾者基類:實現ICoffee介面, 並持有一個ICoffee引用
裝飾者子類:繼承裝飾者基類
h.代理模式
靜態代理:代理物件和目標物件實現同一個介面
動態代理:Proxy.newProxyInstance(目標物件類載入器,目標物件介面,InvocationHandler)
Cglib代理: 通過位元組碼處理框架ASM來轉換位元組碼並生成新的類
實現MethodInterceptor介面
重寫intercept方法實現攔截
i.策略模式(Arrays的Comparator)
使用者通過聚合策略介面
傳入具體策略,使用策略方法
j.模板方法模式
定義抽象類,模板方法固定程式碼執行邏輯,定義final
定義鉤子方法,執行可選步驟
k.觀察者模式
Subject介面:註冊,移除,通知Observer方法
Observer介面:更新資料方法
l.責任鏈模式:為請求建立了一個接收者物件的鏈
定義抽象類,包含處理方法, 組合抽象類物件
3.UML類的關係
a.依賴:通過方法引數傳入
b.關聯:1對多
c.繼承
d.實現
e.聚合:成員變數,通過set方法傳遞
f.組合:成員變數,通過建構函式new
JUC
1.使用棧和佇列時,優先ArrayDeque(迴圈陣列), 次選LinkedList
2.優先佇列(最小堆),新增時,新增到末尾,再向上調整, 刪除時,刪除第一個,末尾補位,再向下調整
3.Map集合
HashMap:
新增元素:頭插法(1.7), 尾插法(1.8)
死迴圈出現條件:
JDK1.7版本
多執行緒put資料(addEntry)
觸發擴容操作(resize)
移動資料階段(transfer)
掛起程式碼行:Entry<K,V> next = e.next;
查詢迴圈連結串列中不存在的元素
還存在丟失資料問題
LinkedHashMap實現LRU
accessOrder 訪問順序
removeEldestEntry() 返回true
TreeMap: 紅黑樹實現
1.每個節點要麼是黑色,要麼是紅色
2.根節點必須是黑色
3.紅色節點不能連續
4.從某個節點出發的所有路徑,黑色個數相同
5.所有的葉子節點都是空節點, 並且是黑色的
4.執行緒
執行緒狀態
新建(New)
可執行(Runnable)
阻塞(Blocking)
無限期等待(Waiting)
限期等待(Timed Waiting)
死亡(Terminated)
執行緒使用方式
實現Runnable介面
實現Callable介面
繼承Thread類
守護執行緒:Daemon, 垃圾回收執行緒
sleep():讓出cpu資源,不會釋放鎖資源
wait(): 讓出cpu資源和鎖資源
sleep()和yield()是Thread類的靜態方法
join()是由執行緒物件來呼叫
wait(),notify(),notifyAll()是Object的方法
yield()只是使執行緒回到可執行狀態
說說程序和執行緒的區別?
程序是程式的一次執行,是系統進行資源分配和排程的獨立單位,作用是程式能併發執行提高資源利用率和吞吐率
因為程序的建立、銷燬、切換產生大量的時間和空間的開銷,程序的數量不能太多。
執行緒是比程序更小的能獨立執行的基本單元,是程序的一個實體,可以減少程式併發執行時的時間和空間的開銷,使作業系統具有更好的併發性。
5.synchronized(原子類內建鎖, 監視器鎖, 同步程式碼塊前後加上monitorenter和monitorexit位元組碼指令)
synchronized同步鎖的四種狀態
無鎖:當有一個執行緒訪問同步塊時升級成偏向鎖
偏向鎖:有鎖競爭時升級為輕量級鎖
輕量級鎖:自旋十次失敗,升級為重量級鎖
重量級鎖:
synchronized用的鎖是存在Java物件頭裡(Mark Word)
Contention List: 所有請求鎖的執行緒將被首先放置到該競爭佇列
Entry List: Contention List中那些有資格成為候選人的執行緒被移到Entry List
Wait Set: 那些呼叫wait方法被阻塞的執行緒被放置到Wait Set
monitorexit退出兩次,第一次正常同步程式碼塊結束釋放鎖,第二次是防止同步程式碼塊出現異常
6.happens-before
程式順序規則
監視器鎖規則:加鎖先發生於解鎖
volatile變數原則:對一個volatitle域的寫先發生於後續對這個volatile域的讀
傳遞性
start()原則:子執行緒能夠看到主執行緒在啟動子執行緒前的操作
join()原則
7.volatile
記憶體屏障(禁止處理器重排序)
StoreStore屏障 volatile寫 StoreLoad屏障
volatile讀 LoadLoad屏障 LoadStore屏障
8.final
對final型別的類擴充套件: 使用組合
final方法是可以被過載的
不是所有的final修飾的欄位都是編譯期常量,只是在初始化後無法被修改
final修飾的欄位可以在構造器中賦值(static同時修飾的除外)
寫final域的重排序可以確保:在物件引用為任意執行緒可見之前,物件的final域已經被正確初始化過了
讀final域的重排序可以確保:在讀一個物件的final域之前,一定會先讀包含這個final域的物件的引用
9.原子類
ABA問題解決:
AtomicStampedReference(版本號)
AtomicMarkableReference(boolean型別標記是否修改)
10.LockSupport
Condition.await()底層是呼叫LockSupport.park()來實現阻塞
LockSupport.park() 不會釋放鎖資源
LockSupport先呼叫unpark,再呼叫park也能實現同步
先呼叫notify,後呼叫wait會出現阻塞
11.AbstractQueuedSynchronizer
內部維護一個state狀態位,嘗試加鎖的時候,通過CAS修改值
AQS是一個用來構建鎖和同步器的框架
使用AQS能簡單且高效地構建出應用廣泛的大量的同步器
兩種資源獲取方式:獨佔,共享
AQS中的佇列是CLH變體的虛擬雙向佇列
addWaiter就是一個在雙端連結串列新增尾結點
雙端連結串列的頭結點是一個無參建構函式的頭結點
跳出當前迴圈的條件是“當前置節點是頭結點,且當前執行緒獲取鎖成功”
判斷前置節點的狀態(waitStatus為-1)來決定是否將當前執行緒掛起
12. ReentrantLock實現了Lock介面
預設使用非公平鎖
Sync、NonfairSync、FairSync三個內部類
13. ReentrantReadWriteLock
ReentrantReadWriteLock實現了ReadWriteLock介面
鎖降級指的是寫鎖降級成為讀鎖
14. ConcurrentHashMap
HashTable : 使用了synchronized關鍵字對put等操作進行加鎖
ConcurrentHashMap JDK1.7: 使用分段鎖機制實現
ConcurrentHashMap JDK1.8: 則使用陣列+連結串列+紅黑樹資料結構和CAS原子操作實現
15. FutureTask:獲取任務執行結果(get)和取消任務(cancel)
16. CountDownLatch
使用場景:電商的詳情頁,由眾多的資料拼接組成,併發獲取資料,並封裝資料
await的呼叫會轉發為對Sync的acquireSharedInterruptibly(從AQS繼承的方法)方法的呼叫
主要方法:await(),countDown()
17. CyclicBarrier:ReentrantLock和Condition的組合使用
使用場景:用於多執行緒計算資料,最後合併計算結果的場景
CountDownLatch減計數,CyclicBarrier加計數
CountDownLatch是一次性的,CyclicBarrier可以重用
CountDownLatch的下一步的動作實施者是主執行緒,具有不可重複性;而CyclicBarrier的下一步動作實施者還是“其他執行緒”本身,具有往復多次實施動作的特點
18. Semaphore(訊號量):通常用於那些資源有明確訪問數量限制的場景,常用於限流
令牌沒有重入的概念。你只要呼叫一次acquire方法,就需要有一個令牌才能繼續執行
release會新增令牌,並不會以初始化的大小為準
Semaphore中release方法的呼叫並沒有限制要在acquire後呼叫
19. Exchanger
用於進行兩個執行緒之間的資料交換
20. ThreadLocal
ThreadLocal是一個將在多執行緒中為每一個執行緒建立單獨的變數副本的類
多個執行緒互相不可見,因此多執行緒操作該變數不必加鎖,適合不同執行緒使用不同變數值的場景
ThreadLocal被提到應用最多的是session管理和資料庫連結管理
每個Thread維護了ThreadLocal.ThreadLocalMap物件,物件中包含的以ThreadLocal為key的entry
ThreadLocal物件是採用弱引用, value變數值本身是通過強引用引入
在程式碼邏輯中使用完ThreadLocal,都要呼叫remove方法,及時清理
ThreadLocal一般加static修飾,同時要遵循第一條及時清理
使用場景:用來儲存session, 資料庫連線
JVM
1.類位元組碼
class檔案本質上是一個以8位位元組為基礎單位的二進位制流
每個class檔案的頭4個位元組成為魔數(cafe babe),用於確定檔案是一個class檔案
2.類載入機制
載入:
1.獲取二進位制位元組流
2.轉化方法區的執行時資料結構
3.Java堆中生成這個類的物件
驗證:
檔案格式驗證,元資料驗證,位元組碼驗證,符號引用驗證(不是必須的)
準備:
為類的靜態變數分配記憶體(方法區),並將其初始化為預設值
解析:
把類中的符號引用轉換為直接引用
初始化:
為類的靜態變數賦予正確的初始值
只有當對類的主動使用的時候才會導致類的初始化
類載入器:
啟動類載入器(Bootstrap ClassLoade),無法被Java程式設計師直接引用
擴充套件類載入器(Extension ClassLoader)
應用程式類載入器(Application ClassLoade)
自定義類載入器
全盤負責:當一個類載入器負責載入某個Class時,該Class所依賴的和引用的其他Class也將由該類載入器負責載入
快取機制:快取機制將會保證所有載入過的Class都會被快取
雙親委派機制
雙親委派優勢:
1.系統類防止記憶體彙總出現多份同樣的位元組碼
2.保證Java程式安全穩定執行
3.JVM記憶體結構
執行緒私有:程式計數器、虛擬機器棧、本地方法區
執行緒共享:堆、方法區、堆外記憶體
程式計數器
1.執行緒私有,記錄JVM位元組碼指令地址
2.唯一一個在JVM規範中沒有規定任何 OOM 情況的區域
虛擬機器棧
1.棧不存在垃圾回收問題
2.棧中的資料是以棧幀的格式存在
3.棧幀中儲存著:區域性變量表、運算元棧、動態連結、方法返回地址、一些附加資訊
本地方法區
與Java環境外互動、與作業系統互動
堆記憶體
1.新生代、老年代、元空間
2.-Xms設定初始記憶體、-Xmx設定最大記憶體, 通常-Xms和-Xmx配置相同的值,目的是垃圾回收完不再重新分隔計算堆的大小,提高效能
3.TLAB(快速分配策略),避免執行緒安全問題,提升記憶體分配的吞吐量
4.逃逸分析:棧上分配(成員變數賦值,方法返回值,例項引用傳遞)、標量替換、鎖消除
方法區
1.用來儲存類資訊、常量池、靜態變數、編譯器編譯後的程式碼快取
4.java記憶體模型
重排序:編譯器重排序、處理器重排序
happens-before 僅僅要求前一個操作(執行的結果)對後一個操作可見
as-if-serial 語義保證不管怎麼重排序,單執行緒程式的 執行結果不能被改變
5.垃圾回收
a.判斷一個物件是否可被回收
1.引用計數演算法
2.可達性分析演算法
b.引用型別:強引用,軟引用,弱引用,虛引用
c.垃圾回收演算法
1.標記-清除
2.標記-整理
3.複製
4.分代收集(新生代使用複製演算法, 老年代使用標記清除/整理)
d.垃圾收集器
1.Serial收集器(序列,單執行緒)
2.ParNew收集器(序列,多執行緒)
3.Parallel Scavenge收集器(序列,多執行緒,吞吐量優先)
4.Serial Old收集器
5.Parallel Old收集器
6.CMS收集器(初始標記,併發標記,重新標記,併發清除)
7.G1收集器(初始標記,併發標記,最終標記,篩選回收)
每個Region都有一個Remembered Set, 用來記錄該Region物件的引用物件所在的Region
整體來看是基於”標記-整理“演算法實現的,從區域性看是基於”複製“演算法實現的
e.記憶體分配策略
1.物件優先在Eden分配
2.大物件直接進入老年代
3.長期存活的物件進入老年代
4.動態物件年齡判定
5.空間分配擔保:老年代的最大可用連續空間是否大於歷次晉升到老年代的物件的平均大小
f.Full GC的觸發條件
1.呼叫System.gc()
2.老年代空間不足
3.空間分配擔保失敗
4.JDK1.7及以前的永久代空間不足
5.Concurrent Mode Failure
6.垃圾回收器G1
預設將整堆劃分為2048個分割槽
每個分割槽內部分成若干大小為512Byte的卡片
併發標記演算法(三色標記法)
G1的收集都是根據收集集合(CSet)進行操作的
產生漏標的原因:黑色物件指向了白色物件,灰色物件指向白色物件的引用消失
7.JVM引數調優
-Xms,-Xmx(最小,最大堆記憶體,一般兩個值相等)
-Xmn(新生代大小,一般為整個堆的1/4或者1/3)
-Xss(堆疊大小,預設為1M)
-XX:NewRatio(新生代與老年代比值)
-XX:MaxPermSize(持久代最大值 64M)
-XX:MaxTenuringThreshold(新生代物件存活次數 15)
8.垃圾回收機制
minor gc: 年輕代發生的
full gc: 老年代的連續空間小於新生代物件的總大小(擔保機制)
永久代(Java虛擬機器): 不屬於堆記憶體,存放jvm執行時需要的類, full gc也會回收永久代
元空間(代替永久代, 使用本地記憶體)
9.Java OOM分析
Java堆記憶體溢位:
配置-XX:+HeapDumpOutofMemoryErorr
分析dump檔案的堆疊資訊
10.Java執行緒Dump分析: jstack [-l ] <pid> | tee -a jstack.log(獲取ThreadDump)
CPU飆高,load高,響應很慢
1.一個請求過程中多次dump
2.對比多次dump檔案的runnable執行緒,觀察是否在執行同一個方法
查詢佔用CPU最多的執行緒
1.使用命令:top -H -p pid,找到導致CPU高的執行緒ID
2.在thread dump中,查詢對應的執行緒堆疊資訊
CPU使用率不高但是響應很慢
進行dump,檢視是否有很多執行緒struct在了i/o、資料庫等地方
請求無法響應
多次dump, 對比是否所有的runnable執行緒都一直在執行相同的方法
11.Java問題排查:Linux命令
文字查詢 - grep (-i 忽略大小寫, -c 統計匹配到的行數)
文字分析 - awk (NR, FNR, NF)
文字處理 - sed (文字列印、替換、插入、刪除)
網路介面屬性 - ifconfig
防火牆設定 - iptables -L
路由表 - route -n
監聽埠 - netstat -lntp
記憶體使用 - free -m
分割槽使用情況 - df -h
指定目錄大小 - du -sh
12.Java問題排查:工具單
jps: 檢視當前Java程序(原理Java程式在啟動後會在java.io.tmpdir目錄下生成一個臨時資料夾,展示的就是資料夾裡檔名)
jstack: jdk自帶的執行緒堆疊分析工具
jinfo: 檢視正在執行的Java應用程式的擴充套件引數
jmap: 可以生成java程式的dump檔案(jmap -dump:live,format=b,file=/tmp/heap2.bin 2815)
jstat: jstat -gcutil 2815 1000
btrace:
1.監控誰呼叫了方法
2.監控方法被呼叫的返回值和請求引數
Greys:
sc -df xxx: 輸出當前類的詳情,包括原始碼位置和classloader結構
trace class method: 打印出當前方法呼叫的耗時情況
Arthas: 是基於Greys
javOSize: classes 通過修改了位元組碼,改變了類的內容,即時生效
JProfiler:
13.評判GC的兩個核心指標
延遲:最大停頓時間,越短越好
吞吐量:程式執行時間佔系統總執行時間的百分比
一次停頓的時間不超過應用服務的TP9999, GC的吞吐量不小於99.99%
14.9中常見的CMS GC問題分析與解決
1.動態擴容引起的空間動盪
現象:剛啟動時GC次數較多,經歷一次GC,堆內各個空間的大小會被調整
解決:儘量將成對出現的空間大小配置引數設定成固定的,如 -Xms 和 -Xmx
2.MetaSpace區OOM
現象:MetaSpace 的已使用大小在持續增長,同時每次 GC 也無法釋放,調大 MetaSpace 空間也無法徹底解決
解決:基本都集中在反射、Javasisit 位元組碼增強、CGLIB 動態代理、OSGi 自定義類載入器等的技術點上,及時給 MetaSpace 區的使用率加一個監控
3.過早晉升
現象:分配速率接近於晉升速率,物件晉升年齡較小;Full GC比較頻繁,經歷過一次GC後Old區的變化比例非常大
解決:根據業務合理調整Young區和old比例,兩次Young GC的時間間隔要大於Tp9999時間
4.CMS Old GC頻繁
現象:Old區頻繁的做CMS GC
解決:分析Dump檔案, 分析Dump Diff, 分析Leak Suspects, 分析Top Component, 分析Unreachable
5.單次CMS Old GC耗時長
現象:CMS GC單次STW最大超過1000ms
解決:大部分問題都出現在Final Remark過程,基本都集中在Reference和Class等元資料處理上,Reference方面分析dump快照(Socket的SocksSocketImpl, Jersey 的 ClientRuntime、MySQL 的 ConnectionImpl),Class方面關閉類解除安裝開關
6.記憶體碎片&收集器退化
現象:併發的CMS GC演算法,退化為Foreground單執行緒序列GC模式
解決:
1.記憶體碎片,配置-XX:UseCMSCompactAtFullCollection=true 來控制 Full GC的過程中是否進行空間的整理
以及 -XX:CMSFullGCsBeforeCompaction=n 來控制多少次 Full GC 後進行一次壓縮
2.增量收集:降低觸發CMS GC的閾值,-XX:CMSInitiatingOccupancyFraction,讓CMS GC儘早執行
3.浮動垃圾:縮短每次CMS GC的時間,必要時可調節NewRatio的值
7.堆外記憶體OOM
現象:記憶體使用率不斷上升
解決:主動申請的堆外記憶體及時釋放,通過JNI呼叫的Native Code申請的記憶體及時釋放
8.JNI引發的GC問題
現象:出現GCLocker Initiated GC
解決:慎用JNI
Redis
1.Redis的資料結構
字串String(動態字串SDS, 空間預分配,惰性空間釋放,二進位制安全)
字典Hash
列表List
集合Set
有序集合SortedSet
HyperLogLog: 能夠提供不精確的去重計數(伯努利實驗),可以用來統計UV
Geospatial: 實時經緯度,geohash技術就是將經緯度轉換成12個字元的字串
Pub/Sub:釋出訂閱
bitmap: 本質是String,512MB, 基數小的時候浪費空間
RoaringBitmap:
.高16位作為索引,低16位儲存資料,最多有2^16個塊,每個塊最多存2^16個數據
.ArrayContainer, BitmapContainer, RunContainer(通過runOptimize方法裝換)
BloomFilter:檢索一個元素是否在一個集合中(redis4.0通過module形式使用)
Pipeline: 可以批量執行一組指令,一次性返回全部結果
Lua:Redis支援提交Lua指令碼來執行一系列的功能(型別Redis事務)
2.常見問題實現
.分散式鎖使用set方法,並設定過期時間
.使用keys指令掃出指定模式的key列表(keys會阻塞服務, scan無阻塞)
.使用list作為佇列,rpush生產訊息, lpop消費訊息, blpop阻塞到訊息到來
.pub/sub主題訂閱模式,可以實現1:N的訊息佇列(消費者下線的情況,生產的訊息會丟失,使用專業的訊息佇列)
.sortedSet實現延時佇列,時間戳作為score, 訊息內容作為key呼叫zadd生產訊息,zrangebyscore獲取資料
.RDB做映象全量持久化,AOF做增量持久化,AOF日誌sync屬性控制同步頻次
.RDB的原理是:fork和cow, fork是通過建立子執行緒來進行RDB操作,cow指的是 copy on write
.PipeLine可以將多次IO往返的時間縮減為一次
.Redis可以使用主從同步,從從同步,第一次同步,主節點做一次bgsave,並同時將後續操作記錄到記憶體buffer,RDB檔案全量同步到複製節點,
複製節點載入完成資料後再同步期間的修改操作,後續的增量資料通過AOF日誌同步即可。
.Redis Sentinal著眼於高可用,在master宕機時會自動將slave提升為master
.Redis Cluster著眼於擴充套件性,在單個redis記憶體不足時,使用Cluster進行分片儲存
3.Bloom Filter分析
原理:當一個元素被加入集合時,通過K個雜湊函式將這個元素對映成一個位數組中的K個點,把他們置為1, 如果這些點有任何一個0,被檢元素一定不在
應用:爬蟲過濾,垃圾郵件過濾
4.Redis哨兵、持久化、主從
.哨兵叢集sentinel:哨兵必須要用三個例項去保證健壯性
.Redis的過期策略,是有定期刪除+惰性刪除兩種
.記憶體淘汰機制LRU
.主從模式下,當主伺服器宕機後,需要人工干預,還會造成一段時間服務不可用(記憶體可用性較低,較難支援線上擴容)
.哨兵模式下,哨兵會自動選舉master並將其他的slave指向新的master。 哨兵是一個獨立的程序
.當哨兵監測到master宕機,會自動將slave切換到master,通過釋出訂閱模式通知其他從伺服器,修改配置檔案,切換主機
.叢集模式(redis3.0):實現redis的分散式儲存,對資料進行分片, 插槽(0-16383),CRC16演算法
.如果master1和它的從節點slave1都宕機了,整個叢集就會進入fail狀態,因為叢集的slot對映不完整。
如果叢集超過半數以上的master掛掉,無論是否有slave,叢集都會進入fail狀態。
.一致性hash演算法的Java實現是使用TreeMap
5.Redis雙寫一致性、併發競爭、執行緒模型
.最經典的快取+資料庫讀寫模式
先讀快取,沒有的話讀資料庫,然後取出放快取,返回響應
更新的時候,先更新資料庫,然後再刪除快取
.Redis和Memcached有啥區別
Redis支援複雜的資料結構
Redis原生支援叢集模式
儲存小資料Redis效能高,儲存100k以上大資料Memcached效能高
.Redis的執行緒模型
Redis內部使用檔案事件處理器file event handler, 是單執行緒的。採用IO多路複用機制同時監聽多個Socket
檔案事件處理器的結構
.多個Socket
.IO多路複用程式
.檔案事件分派器
.事件處理器(連結應答處理器、命令請求處理器、命令回覆處理器)
6.Memcache優缺點
.處理請求時使用多執行緒非同步IO的方式,可以合理使用CPU多核的優勢
.key不能超過250個位元組
.value不能超過1M位元組
.key的最大失效時間是30天
.只支援k-v結構,不提供持久化和主從同步功能
7.Redis分散式鎖-紅鎖
set分散式鎖(2.6.12以後)問題:業務執行時間大於鎖超時時間,被其他執行緒提前獲取鎖或者刪鎖,不可重入, 無法自動續期
解決:value設定UUID隨機數,刪除鎖之前先進行判斷(Lua指令碼)
問題:請求一個分散式鎖的時候,成功了,但是slave還沒複製我們的鎖,master掛掉了,再請求鎖的時候,也會成功。同一個鎖獲取了不止一次。
原理:Redisson
.獲取當前的時間
.使用相同的key和隨機值在N個節點上請求鎖
.只有大多數節點獲取到了鎖,且總的獲取時間小於鎖的超時時間情況下,鎖獲取成功
.如果鎖獲取成功了,鎖的超時時間是最初的超時時間減去獲取鎖的總耗時時間
.如果獲取鎖失敗了,將都已經設定了key的master上的key刪除
.通過看門狗檢查並續期(開啟Watch Dog機制必須使用預設的加鎖時間30秒, 自定義時間不會自動續期)
8.秒殺系統設計
問題:高併發,超賣,惡意請求,連結暴露,資料庫
解決:服務單一職責,秒殺連結加鹽,Redis叢集,Nginx, 資源靜態化,按鈕控制,限流,風控,庫存預熱, 限流&降級&熔斷&隔離,削峰填谷,分散式事務
9.快取必問三個問題
快取穿透:訪問資料庫不存在的資料(引數校驗,空資料快取,布隆過濾器)
快取擊穿:熱點key過期,設定熱點key永不過期
快取雪崩:同一時間點大量key過期,過期時間加隨機數
10.跳錶
每隔一個節點就提取出來一個元素到上層,把這一層稱作為索引
構建跳錶:N個節點構建跳錶將需要logn層索引,包括自身那層連結串列層
11.分散式鎖
利用setnx+expire命令:不具有原子性,會出現鎖無法過期(Lua指令碼來保證原子性)
利用set命令(2.6.12):value必須具有唯一性,釋放鎖時,對value進行驗證
Mysql
1.索引
資料結構:hash(等值查詢,只有KV的情況), 有序陣列(靜態資料), 二叉樹(樹會很高), B+(提高磁碟IO效率,範圍查詢效率,有序)
一個B+樹的節點中到底存多少個元素最合適?
結論:B+樹中一個節點為一頁(16KB)或頁的倍數最為合適(1200叉)
原理:mysql的基本資料結構是頁,各個資料頁組成一個雙向連結串列, 資料頁中的記錄組成一個單向列表, 每個頁有一個頁目錄,通過主鍵可以二分查詢
回表:回到主鍵索引樹搜尋的過程(通過覆蓋索引避免)
覆蓋索引:一個查詢語句的執行只從索引中就能取到,不必從資料表中讀取,可以減少樹的搜尋次數
索引選擇原則:最左字首匹配原則,區分度高的列作為索引,索引不能參與計算,儘可能的擴充套件索引
聚集索引:以主鍵建立的索引
非聚集索引:除主鍵以外的索引
磁碟IO: 尋道,尋點,拷貝到記憶體(預讀會把相鄰的資料也讀取到記憶體緩衝區中。索引目的儘量減少磁碟的IO操作)
全文索引:MyISAM支援,用於查詢文字中的關鍵字,使用倒排索引實現
空間資料索引:用於地理資料儲存,會從所有維度來索引資料
字首索引:對於BLOB, TEXT和VARCHAR型別的列,必須使用字首索引,只索引開始的部分字元(定義好長度,既節省空間,又不用增加太多查詢成本)
索引下推:在索引遍歷過程中,對索引中包含的欄位先做判斷,直接過濾掉不滿足條件的記錄,減少回表次數
2.鎖
MVCC版本控制
作用:用於實現讀已提交和可重複讀這兩種隔離級別
基礎概念:系統版本號(遞增的數字),事務版本號(事務開始時的系統版本號)
Undo日誌:MVCC的快照儲存在Undo日誌中,通過回滾指標把一個個資料行的所有快照連線起來
gap鎖(鎖左右間隙,開區間)
語句:SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
作用:保證可重複讀的情況下不出現幻讀
原理:鎖住索引樹的葉子節點之前的間隙,不讓新的記錄插入到間隙之中
Next-Key鎖(前開後閉)
是Record鎖和gap鎖的結合,不僅鎖定一個記錄上的索引,也鎖定索引之間的間隙
SELECT操作的不可重複讀問題通過MVCC解決
UPDATE、DELECT的不可重複讀通過Record鎖解決
INSERT的不可重複讀是通過Next-Key鎖解決
鎖問題
髒讀:當前事務讀取到另外事務未提交的資料
不可重複讀:同一個事務內多次讀取同一個資料集合,讀取到的資料是不一樣的情況
幻讀:讀到不存在的行(新插入的行)
丟失更新:一個事務的更新操作會被另一個事務的更新操作所覆蓋
3.儲存引擎
InnoDB: 支援事務,支援行級鎖,支援外來鍵,支援線上熱備份
MyISAM: 不支援事務,支援表級鎖,支援壓縮表和空間資料索引
4.事務
原子性(A),一致性(C),隔離性(I),永續性(D)
隔離級別:讀未提交(返回最新值),讀已提交(每個sql開始時建立檢視),可重複讀(事務啟動時建立檢視,MVCC + Next-Key Locking防止幻讀),序列化
5.查詢效能優化
使用explain分析select查詢語句,索引查詢型別(system, const, ref, range, index, all)
優化資料查詢:減少請求的資料量(只查詢必要的列,只返回必要的行,快取重複查詢的資料),減少資料庫掃描的行數
重構查詢方式:做分頁,分批查詢
6.分庫分表資料切分
水平切分:Sharding, 分割槽
垂直切分:分表,分庫
7.主從複製
binlog執行緒:負責將主伺服器上的資料更改寫入二進位制日誌binlog中
I/O執行緒:負責從主伺服器上讀取二進位制檔案,並寫入從伺服器的中繼日誌Relay log
SQL執行緒:負責讀取中繼日誌,解析已經執行的資料更改並在從伺服器中重放
8.讀寫分離:主伺服器處理寫操作以及實時性要求比較高的讀操作,從伺服器處理讀操作,代理方式實現
9.架構
server層
聯結器:管理連線,許可權驗證
查詢快取:命中則直接返回結果
分析器:詞法分析,語法分析
優化器:執行計劃生成,索引選擇
執行器:操作引擎,返回結果
儲存引擎:InnoDB, MyISAM, Memory
10.重要的日誌模組
.redo log(InnoDB,獨有): 先寫日誌,再寫磁碟, 4個檔案共4G, write pos是當前記錄要寫的位置,checkpoint是當前要擦除的位置,保證資料庫異常重啟,之前提交記錄不丟失(crash-safe)
.binlog(Server層,格式:statement(會出現主備不一致),row): 追加寫, 事務執行過程中先把日誌寫到binlog cache,事務提交的時候,再把binlog cache寫到binlog檔案中
11.字首索引重複太多解決:倒序儲存,使用hash欄位(不支援範圍掃描)
12.統計數量效率 count(欄位) < count(主鍵id) < count(1) ~ count(*)
13.常見使用不到索引的情況
.對索引欄位做函式操作
.欄位隱式型別轉換
.欄位隱式字元編碼轉換
14.GTID模式(複製方式)
通過GTID保證了每個在主庫上提交的事務在叢集中有一個唯一的ID,強化了資料庫的主備一致性,故障恢復以及容錯能力
單點登入:在多個系統中,使用者只需要一次登入,各個系統即可感知該使用者已經登入
登入功能抽取為一個系統
將使用者資訊存在Redis
輸入網址後,期間發生了什麼?
.解析url
.真實地址查詢-DNS(本地DNS伺服器,如果有快取直接返回, 根域名伺服器, 頂級域名伺服器,權威域名伺服器)
.建立TCP連線
.使用HTTP協議請求網頁內容
.渲染
TCP三次握手的作用
.防止歷史連線的建立
.減少雙方不必要的資源開銷
.幫助雙方同步初始化序列號
TCP四次揮手,主動關閉連線的為什麼需要TIME_WAIT狀態?
防止具有相同四元組的舊資料包被收到
保證被動關閉連線的一方能被正確的關閉
TCP的重傳機制、滑動視窗、流量控制、擁塞控制
重傳機制:
超時重傳:超時重傳時間RTO的值應該略大於報文往返RTT的值
快速重傳:當收到三個相同的ACK報文時,會在定時器過期之前,重傳丟失的報文段
SACK方法:需要在TCP頭部欄位里加一個SACK的東西,它可以將快取的地圖傳送給傳送方
Duplicate SACK: 可以讓傳送方知道是發出去的包丟了,還是接收方迴應的ACK包丟了
滑動視窗:
視窗大小:無需等待確認應答,而可以繼續傳送資料的最大值
方案:3個指標來跟蹤在四個傳輸類別中的每一個類別中的位元組
流量控制:讓傳送方根據接收方的實際接收能力控制傳送的資料量
視窗關閉
擁塞控制:避免傳送方的資料填滿整個網路(擁塞視窗)
慢啟動:發包個數是指數性的增長
擁塞避免:當擁塞視窗cwnd超過慢啟動門限ssthresh(65535位元組)就會進入擁塞避免演算法, 每當收到一個ACK,cwnd增加1/cwnd
擁塞發生:超時重傳(ssthresh設為cwnd/2, cwnd重置為1),快速重傳(cwnd設為cwnd/2, ssthresh = cwnd)
快速恢復:cwnd = ssthresh+3, 重傳丟失的資料包, 如果再收到重複的ACK, cwnd增加1, 如果收到新資料的ACK, cwnd = ssthresh
TCP頭的格式:TCP是面向連線的,可靠的,基於位元組流的傳輸層通訊協議
序列號:在建立連線時由計算機生成的隨機數作為其初始化值, 用來解決網路包亂序問題
確認應答號:用來解決不丟包問題
網路七層協議:應用層,表示層,會話層,傳輸層,網路層,資料鏈路層,物理層
Zookeeper投票規則:
當其他節點的記元比自己高投它
紀元相同比較自身的zxid的大小(提交事務最大的id)
如果epoch和zxid都相等,則比較服務的serverId, 最大的當選
Zookeeper是如何保證資料一致性的
通過ZAB原子廣播協議來實現資料的最終順序一致性
Kafka為什麼那麼快?
順序寫:partition劃分為多個Segment, 每個Segment對應一個物理檔案,Kafka對segment檔案追加寫
Memory Mapped Files: 直接利用作業系統的Page來實現檔案到實體記憶體的對映
零拷貝:sendfile
批量與壓縮:壓縮演算法lz4, snappy,gzip
分割槽併發:
檔案結構:稀疏索引
Kafka如何保證訊息佇列不丟失
ACK機制:0 傳送即算成功 1 leader接收並寫入分割槽算成功 -1 所有同步副本接收並寫入成功
分割槽副本
關閉unclean leader選舉
面對百億資料,Hbase為什麼查詢速度依然非常快
資料儲存在Hbase叢集上(多個數據節點,每個資料節點上有若干個Region)
根據主鍵Rowkey查詢對應記錄,Hbase的Master快速定位到記錄所在的資料節點和節點中的Region
由於Hbase儲存資料是按照列簇儲存的,只查詢對應的列簇資料
列簇底層包含多個HFile檔案(100M)
每個HFile中,是以鍵值對方式儲存,遍歷檔案中的key位置即可
網路效能指標
頻寬:表示鏈路的最大傳輸速率,單位是b/s,頻寬越大,其傳輸能力越強
延時:表示請求資料包傳送以後,收到對端響應,所需要的時間延遲
吞吐率:表示單位時間內成功傳輸的資料量,單位是b/s
PPS:表示以網路包為單位的傳輸速率
Hbase規格配置
Master節點資訊:8核32G, 2個節點
Core節點資訊:8核32G, 8個節點, 單節點容量1520G
ClickHouse規格配置
規格:S104 104核384GB, 節點組個數:10, 磁碟空間 3000GB
排序演算法 時間複雜度 空間複雜度 穩定性
插入排序 O(n^2) O(1) 穩定
氣泡排序 O(n^2) O(1) 穩定
選擇排序 O(n^2) O(1) 不穩定
快速排序 O(nlog2n) O(log2n) 不穩定
堆排序 O(nlog2n) O(1) 不穩定
歸併排序 O(nlog2n) O(n) 穩定
堆排序:把最大堆堆頂的最大數取出,將剩餘的堆繼續調整為最大堆,再次將堆頂的最大數取出
歸併排序:通過先遞迴分解陣列,再合併陣列
使用者標籤資訊bitmap儲存: 標籤名,標籤值,bitmap資料(user_id)
不使用ES的原因
新增或修改標籤,不能實時進行,涉及到ES文件結構的變化
ES對資源消耗比較大,屬於豪華型配置
ES的DSL語法對使用者不太友好,使用者學習成本高
人群介面服務,rt波動較大問題解決
jvm預熱:類載入過程完畢後,所有需要的類會進入JVM cache, 這樣就可以被快速的實時訪問,當然,還有很多其他與JVM啟動無關的類此時並未被載入
當應用的第一個請求到來,會觸發邏輯相關類的第一次載入,會影響第一次呼叫的實時響應,這主要是因為JVM的懶載入及JIT機制(即時編譯技術)
因此對於低延遲應用,必須採用特定的策略來處理第一次的預載入邏輯,以保障第一次請求的快速響應(改變consul健康檢查路徑,預熱200次)
優化程式碼(日誌縮減):
logback非同步日誌效能沒有log4j2非同步日誌效能高,因為log4j2的非同步日誌有Disruptor環形無鎖佇列支援
不要使用System.currentTimeMillis()來獲取時間, 使用虛擬時鐘來進行時間獲取SystemLocalTime.millisClock().now()
GC引數調整:hbase開啟堆外記憶體,使用混合回收模式
undertow工作執行緒數增加:增加到2048
-XX:+UseG1GC 使用G1垃圾回收器
-XX:+UnlockExperimentalVMOptions 允許使用實驗性引數(低版本jdk想使用高階引數)
-XX:G1MaxNewSizePercent=60 年輕代大小最大值的堆大小百分比
-XX:InitiatingHeapOccupancyPercent=30 觸發標記週期的Java堆佔用率閾值
-XX:MaxGCPauseMillis=200 為所需的最長暫停時間設定目標值
-XX:G1HeapRegionSize=16m 設定G1區域的大小
-XX:+PrintGCDetails 列印GC時的記憶體,並且在程式結束時列印堆記憶體使用情況
-XX:+PrintGCDateStamps 輸出GC的時間戳
-XX:+PrintHeapAtGC 列印GC前後堆的概況
-XX:+PrintGCApplicationConcurrentTime 列印每次GC時程式執行的時間
日誌系統:log4j2
讓日誌不影響系統性能的方式:
減少日誌量
不在日誌中做字串拼接,而使用佔位符的方式來拼接日誌
將日誌的記錄方式從同步變成非同步
log4j2三個元件
Logger: 在程式中用來記錄日誌的物件
Layout: 用來對日誌資訊進行格式化
Appender: 用來配置日誌的展現形式(控制檯列印,儲存檔案,資料庫,訊息佇列)
log4j2只在Logger這塊使用了佇列(Disruptor),進行非同步處理
Disruptor: 環形無鎖記憶體佇列
環形陣列結構
元素位置定位(位運算)
無鎖設計:每個生產者或者消費者執行緒,會先申請可以操作的元素在陣列中的位置
事務一般指的是邏輯上的一組操作,或者單個邏輯單元執行的一系列操作。這些操作要麼執行成功,要麼執行失敗。
分散式事務指將海量資料分散的儲存到多臺伺服器的多臺資料庫中,同時要具備 ACID 特性。
C(Consistency)一致性:對所有的資料副本在進行增刪查操作時,要麼全部執行成功,要麼全部執行失敗。
A(Availability)可用性:指客戶端訪問資料的時候,能夠快速得到響應。所有的請求都會被響應,不會存在響應超時或響應錯誤情況
P(Partition Tolerance)分割槽容忍性:一個節點掛掉後,不影響其他節點對外提供服務。
Base 理論是對 CAP 理論中 AP 理論的一個擴充套件,它通過犧牲強一致性來獲得可用性。
Base 理論是 基本可用(Basically Available)、軟狀態(Soft State)、和最終一致性(Eventually Consistent)的縮寫。當系統出現故障時,Base 理論允許部分資料不可用,但是會保證核心功能能用;允許資料在一段時間內不一致,但是經過一段時間,資料最終是一致的。
資料庫隔離級別
未提交讀(Read Uncommitted):允許髒讀,也就是可能讀取到其他會話中未提交事務修改的資料
提交讀(Read Committed):只能讀取到已經提交的資料。Oracle等多數資料庫預設都是該級別 (不重複讀)
可重複讀(Repeated Read):可重複讀。在同一個事務內的查詢都是事務開始時刻一致的,InnoDB預設級別。在SQL標準中,該隔離級別消除了不可重複讀,但是還存在幻象讀
序列讀(Serializable):完全序列化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞
mybatis的一級快取是預設開啟的,它將資料存放在同一個SqlSession物件中。該物件可以粗略的將其理解為"封裝好的資料庫連線"。
mybatis的二級快取是預設關閉的,如果想要使用二級快取,我們需要在mybatis-config.xml檔案中手動配置開啟。二級快取的資料快取在同一個namespace生成的對映物件中
Full GC的觸發條件
1.呼叫System.gc()
2.老年代空間不足
3.空間分配擔保失敗
4.JDK1.7及以前的永久代空間不足
5.Concurrent Mode Failure
Java String類為什麼是final的?
1.為了實現字串池
2.為了執行緒安全
3.為了實現String可以建立HashCode不可變性
JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個屬性和方法
這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為 java語言的反射機制
原理:Java在編譯之後會生成一個class檔案,反射通過位元組碼檔案找到其類中的方法和屬性
記憶體洩露是指物件不再被應用使用,但是GC卻不能將其從記憶體中釋放
一種非常普遍的記憶體洩露場景是靜態的域成員持有物件引用
一種非常普遍的記憶體洩露場景就是對要放入HashSet中的物件,缺少hashCode或者equals方法
(1)如果要操作少量的資料用 String;
(2)多執行緒操作字串緩衝區下操作大量資料 StringBuffer;
(3)單執行緒操作字串緩衝區下操作大量資料 StringBuilder(推薦使用)
Docker:是指容器化技術,用於建立和使用Linux容器
作用:藉助docker,可將容器當做輕巧、模組化的虛擬機器使用。同時,還將獲得高度的靈活性,從而實現對容器的高效建立,部署和複製,並能將其從一個環境順利遷移到另一個環境,從而有助於針對雲來優化應用。
原理:docker技術使用Linux核心和核心功能來分隔程序,以便各程序相互獨立執行。這種獨立性正式採用容器的目的所在。
redis叢集為什麼有16384個槽?
1.如果槽位是65536,傳送心跳資訊的訊息頭達8k,過於龐大
2.redis的叢集主節點數量基本不可能超過1000個
3.槽位越小,節點少的情況下,壓縮比高
腦裂:同一個叢集中的不同節點,對於叢集的狀態有了不一樣的理解
哨兵模式造成的redis腦裂現象原因?
由於網路原因或者一些特殊原因,哨兵失去了對master節點器的感知,將會通過選舉進行故障轉移,將slave節點提升為master節點,這就導致了當前叢集中有兩個master,這就是腦裂現象的體現
解決方案:通過活躍slave節點數和資料同步延遲時間來限制master節點的寫入操作
synchronized鎖升級過程(無鎖01,偏向鎖01,輕量級鎖00,重量級鎖11)
特點:鎖升級不能降級的策略,為了提高獲得鎖和釋放鎖的效率
三次握手與四次揮手
三次握手是為了建立可靠的資料傳輸通道,四次揮手則是為了保證等資料完全的被接收完再關閉連線
第一次握手:同步報文SYN=1, 隨機序列號seq=x (確認服務端是否有接收和傳送資料的能力)
第二次握手:同步報文SYN=1, ACK=1, seq=y, ack=x+1 (確認客戶端是否有接收資料的能力)
第三次握手:ACK=1, seq=x+1, ack=y+1 (回覆服務端自己有接收資料的能力)
大寫的 ACK 表示報文的型別是確認報文,小寫的 ack 是報文裡面的確認號
第一次揮手:FIN=1, seq=u(客戶端發起關閉連線的請求)
第二次揮手:ACK=1, seq=v, ack=u+1(服務端知道了客戶端要關閉連線,資料還沒傳輸完,需要等待)
第三次揮手:FIN=1,ACK=1,seq=w,ack=u+1(資料傳輸完了,服務端這邊準備關閉連線)
第四次揮手:ACK=1, seq=u+1, ack=w+1(客戶端知道服務端要關閉連線了,等一會)
為什麼握手要三次,揮手卻要四次呢?
因為握手的時候沒有資料傳輸,所以服務端的SYN和ACK報文可以一起傳送,揮手的時候有資料在傳輸,ACK和FIN報文不能同時傳送
為什麼客戶端在第四次揮手以後還會等待2MSL?
等待2MSL是因為保證服務端接收到了ACK報文,如果服務端沒接收到ACK報文的話,會重新發送FIN報文
AQS核心思想是,如果被請求的共享資源空閒,那麼就將當前請求資源的執行緒設定為有效的工作執行緒,將共享資源設定為鎖定狀態;如果共享資源被佔用,就需要一定的阻塞等待喚醒機制來保證鎖分配。這個機制主要用的是CLH佇列的變體實現的,將暫時獲取不到鎖的執行緒加入到佇列中。
AQS中的佇列是CLH變體的虛擬雙向佇列(FIFO),AQS是通過將每條請求共享資源的執行緒封裝成一個節點來實現鎖的分配。
Java中可以作為GC Roots的物件
1.虛擬機器棧中引用的物件
2.方法區中類靜態屬性引用的物件
3.方法區中常量引用的物件
4.本地方法棧中引用的物件