HSF實際上是一個RPC框架,RPC是Remote Procedure Call,就是遠程服務調用.
這個功能爲何要寫個框架而不是十幾行代碼呢,由於在分佈式場景下並非這種點對點通信的模式。
rpc要素:where how
地址:註冊中心ConfigServer, 這個中心用來管理整個分佈式集羣裏全部的服務對應服務提供者ip的對應關係,
這玩意是不能寫在配置文件裏的,在分佈式場景下擴容、縮容機器ip的變化實在是太正常了,
必需要有一個註冊中心來管理地址;hsf的註冊中心是ConfigServer;之前開源的rpc框架dubbo也有本身的 註冊中心,
像twitter的fonango的註冊中心是zk
接口:基於接口編程,不像http請求返回json數據或者json rpc協議或者webservice那樣都有一個共同的問題,
就是對開發人員不友好,換句話說就是須要侵入業務流程,不得不讓上層的調用爲rpc調用寫一些複雜醜陋的代碼web
configServer能夠當作一個具備聚合功能的內存數據庫, 服務提供者將本身的地址和提供的服務註冊到ConfigServer,服務消費者要調用的時候會向ConfigServer查詢,實際上是訂閱這個服務,ConfigServer知道它要訂閱以後會作一個聚合的操做,聚合以前對應關係是ip對應服務列表,聚合以後是服務對應ip列表, 聚合以後會向服務訂閱者推送這個數據,會告訴訂閱者提供這個服務的地址有哪些,後面就沒有ConfigServer的事情了,服務消費者拿到這個地址列表以後會隨機選擇一臺機器發起調用,後面rpc整個流程都是點對點,不牽涉到任何環境的變動。spring
沒有地址列表,談rpc是沒有意義的。 地址列表永遠是rpc這個場景下最最重要的東西;數據庫
ConfigServer是推送模式,不光在消費者第一次訂閱時會推送, 後面每當服務提供者變化時都會推送;
這種推送模型有哪些好的和很差的地方 ?編程
真正的環境只有兩套,一個線上環境和線下環境,它們之間的網絡是隔離的,但預發環境和線上環境是通的,
但怎麼保證預發環境的detail不會調用線上的ic呢?其實靠的就是ConfigServer,預發的ConfigServer和線上的ConfigServer是不一樣的,預發的detail連的是預發的ConfigServer,預發的ConfigServer確定沒有線上ic的地址,全部永遠不會調用到線上的ic,集團的這些環境都是經過中間件的ConfigServer這個產品進行區分的,就是線下環境會有性能環境、二套環境啊,ConfigServer不一樣罷了,裏面的ip列表都不同。json
HSF中服務名約等於接口名
任何HSF編程,都依賴於接口
服務提供接口實現
客戶端基於接口編程,內部HSF代理去進行遠程通訊
客戶端基於接口編程,當客戶端執行到這個接口的時候,客戶端本地是沒有任何實現的,hsf會在內部做代理,
當執行到這個接口的某個方法的時候,hsf會遠程發送一個tcp的請求,發送給這個服務端,服務端在本地執行這個接口的實現,拿到響應以後發送回給這個客戶端,hsf會把這個結果看成這個接口的返回值去給上層的應用;tomcat
隔離容器–Pandora(taobao-hsf.sar)網絡
1.全部中間件(hsf/tddl/notify)都在Pandora內部
2.提供類隔離機制
爲何把他們打在一塊兒,由於Pandora提供了一種類隔離的機制,這樣的好處是當應用特別複雜的時候,會依賴特別多的jar包,而這些jar包可能又會依賴不一樣版本的中間件,排除起來會很是的痛苦,當classpath目錄下有兩個packagename和classname都相同的類的時候,jvm會隨機加載一個,這個時候若是不把多餘的依賴排除乾淨的話,是沒法保證在運行時期所使用的hsf究竟是哪一個版本,若是使用sar包的話,唯一肯定的一點就是hsf就是sar包裏的版本,它只會用sar包裏的版本,還有一點,好比說hsf會依賴google的guava庫,當你的應用也要用guava庫,它們之間是相互隔離的,這個隔離就是經過Pandora來作到的。架構
Web容器–湯姆貓,J老闆
1.HSF和這些玩意其實沒什麼關係
hsf-standalone能夠只用一個main方法就能夠啓動hsf框架
配置文件配置好後,若是是在web容器中使用hsf的,先讓web容器跑起來,web容器會初始化spring,
spring會在beanFactory初始化全部bean的時候幫你把hsf發佈出去,服務就提供出去了,就什麼都不用管了。異步
接口名和版本號做爲一個二元組區分一個hsf服務
深刻性的原理:
隔離容器Pandora
HSF自身架構
軟負載策略
異步調用
線程池
sar是什麼(Pandora就是taobao-hsf.sar,全部的中間件都在裏面,不只是hsf, 只是爲了兼容纔沒更名字)
幹什麼:加載的隔離、模塊化
加載隔離的做用:
模塊化:通常不用關心,pandora-framework來實現應用拆分紅不一樣的組件,即組件化。
怎麼玩的:導出、導入
怎麼實現加載的邏輯的呢,怎麼保證應用必定會用pandora內部的hsf,而不是用當前classpath下依賴的hsf的jar包呢
這就是導出的概念:pandora是生存在web容器中的,好比說tomcat,tomcat針對每個war包,它有它本身的war-classloader這個東西,
這個東西會持有pandora的calssloader,當tomcat要加載類的時候,它會優先從pandora的classloader中加載類,
那pandora的classloader很奇怪也會持有tomcat的classloader,這樣作以後,加載的流程就變爲:
若是pandora中的hsf這個組件把hsfSpringProviderBean這個類選擇導出的話,那麼當tomcat要加載這個類,
也就是應用要加載hsfSpringProviderBean的時候,它會優先從pandora的classloader中去尋找,
那麼pandora發現這個類是被hsf導出的類,它就會把它本身持有的hsf返回給tomcat,tomcat返回給上層的應用。
這樣就保證了在tomcat的deploy目錄下放置pandora的話,使用的hsf版本必定是pandora中的hsf版本.
導入:好比說hsf要使用fastjson,大部分狀況下hsf是不會使用通用的三方庫的(fastjson/commons-lang),
但若是應用通hsf傳輸的DO中包含這些東西,好比應用返回的DO是一個JSONObject的話,那麼hsf就要選擇使用導入這個功能。回到剛剛那個邏輯:tomcat持有pandora的classloader,而後pandora持有tomcat的classloader, hsf是被pandora去加載的,那麼hsf在嘗試加載jsonobject這個類進行反序列化的時候,它會在pandora的classloader中優先尋找,可是pandora的classloader中是不包含這個玩意的,由於hsf自身不依賴它,那麼pandora就會拿它持有的那個tomcat的classloader去load這個class,就是jsonobject,這個就至關於tomcat對於這種導入的類會使用應用自身cp那些類,這就是導入的邏輯, 其實導入真正的使用場景是對於spring這個東西,由於hsf要配置spring才能使用,
可是hsf自身也是依賴spring編程的,而spring-context若是你們依賴的不同的話,會形成多份spring-context,那這樣的話,應用拿不到hsf的類,hsf拿不到應用的類,全部hsf必須和應用用同一份spring-context,因此hsf選擇導入spring。
這就介紹了pandora是怎麼實現加載隔離的,就是兩個概念,一個導入,一個導出;
有什麼好處:對應用無侵入,平滑升級
HSF自身架構
hsf分紅三層:
第一個是Proxy層,主要處理hsf和應用交互的一些邏輯,好比作接口的代理,執行業務的方法
第二個是Remoting層,主要處理網絡層中的應用層數據,它處理的是rpc協議
第三個是Processer層,主要處理hsf自身的一些邏輯,好比說序列化反序列化,異常處理等
處理完全部的邏輯以後,hsf是基於netty編程的,netty負責處理io模塊來進行通訊,這樣的話,
ConfigServer/Diamond與Proxy層進行交互以後,就組成了整個的consumer/provider的調用過程,
軟負載策略–hsf的選址邏輯
什麼是軟負載,說白了就是導流量, 怎麼導流量呢?
第一種方式就是歸組,
軟負載策略–歸組:歸組規則是能夠經過Diamond配置動態推送的,能夠動態的把機器配置成A組別仍是B組別,也有利於動態擴容
軟負載策略–路由:路由規則–經過配置將客戶端流量導到某些機器上。如何配置:Diamond規則,內容是Groovy腳本
與歸組規則區別:粒度到方法參數;有保護機制(有算空保護,即當算出來的ip地址是空的時候會隨機地全量調用)
歸組規則的粒度只能到某個服務,不能到某個方法。
簡單的來看,都是經過配置將流量致使某些機器上, 那何時用歸組規則,何時用路由規則。
軟負載策略–同機房優先:在閥值範圍內,客戶端會優先調用同機房的客戶端
如何篩選同機房ip:
在同一個虛擬機房(HSF邏輯)
ip前兩段相同
閥值的做用:
同機房機器數/總機器數>閥值,會優先調用同機房的機器
同機房機器掛掉->(同機房機器比例<閥值)->隨機調用
權重規則–對於provider集羣中的某些機器,增長被調用到的機率
未配置權重:每臺機器被訪問的機率相同
總機器數爲m,配置某ip的權重爲n後,這個ip被訪問的機率爲:(1+n)/(m+n),
作法就是在m個ip的列表中在塞進去n個相同的ip便可
異步調用有兩種方式Future調用和Callback調用,做用都是差很少的,都是解放真正的調用線程。
我的認爲,大部分的異步場景是能夠經過消息來解決的。 消息是rpc的一種
線程池–HSF的業務線程池
HSF爲全部Provider開一個ThreadPool
支持不一樣的服務配置單獨的線程池
定製化的ThreadPoolExecutor
任務隊列爲SynchronousQueue(不是LinkedBlockingQueue,能夠快速遞交,快速失敗)
線程複用時間爲5min
拒絕策略觸發時會打印Jstack
常見問題:
找不到地址
應用啓動後沒查到本身發佈的服務
超時
序列化錯誤
找不到方法
線程池滿
啓動出錯永遠只看第一個,後面通常都是web context掛掉形成的