
如何快速實現(xiàn)REST API集成以優(yōu)化業(yè)務(wù)流程
面對不同的業(yè)務(wù)集群,作為服務(wù)方需要兼顧靈活和標準, 首先通過從眾多的接口訪問信息中抽出來標準化的數(shù)據(jù)信息集,如集群名稱,接口uri,http Code,訪問量,訪問時長,超時量,失敗量等具體的數(shù)據(jù),標準化的數(shù)據(jù)保證了傳輸?shù)捻槙?,為后續(xù)的分析,統(tǒng)計,展示奠定基礎(chǔ)。其次提供靈活的可配置方案,兼容不同集群,不同采集間隔和自動化uri采集模型,去實現(xiàn)業(yè)務(wù)的靈活變通。
wrm.enable=1
wrm.tick=60
wrm.timeout=2000
wrm.collector_register_url=https://****.**.com/****/****
wrm.collector_port=****
wrm.cluster=***_***_***
wrm.total_url_num=500
wrm.enable_sync_uri=1
wrm.sync_uri_url=****.**.com/****/****
利用PHP的底層特性以擴展形式在PHP進程啟動的時候加載,避免開發(fā)同學(xué)因接入監(jiān)控服務(wù)而需要做出額外的開發(fā),實現(xiàn)無感知的數(shù)據(jù)采集。
合理選型數(shù)據(jù)結(jié)構(gòu)和接入方式,依托于PHP-FPM主進程的監(jiān)控進程,避免對系統(tǒng)額外的cpu和內(nèi)存資源占用,保證線程安全調(diào)用。
1. ?首先啟動PHP Zend引擎后,在注冊動態(tài)擴展的過程中通過調(diào)用MINIT鉤子,fork出來監(jiān)聽進程,從而在每次request開始/結(jié)束時 執(zhí)行業(yè)務(wù)邏輯。
2. 監(jiān)聽根據(jù)系統(tǒng)配置,初始化全局變量如上報時長,內(nèi)存大小,上報地址等信息,以及通過mmap開辟共享內(nèi)存空間和pthread去實現(xiàn)線程安全上報。
3. 每次request在請求時會初始化php_request_startup,并依次遍歷調(diào)用擴展中調(diào)用Rinit,在這個過程中收集到uri,http code,訪問時長等信息存儲如對應(yīng)的結(jié)構(gòu)體。
4. 監(jiān)聽進程根據(jù)配置tick收集指定間隔時間的數(shù)據(jù)后,通過切換數(shù)據(jù)hash的內(nèi)存塊指針,平滑變更hashtable的角色屬性,啟動上報線程,開始壓縮數(shù)據(jù)并異步上報至數(shù)據(jù)中心服務(wù)側(cè)。
PHP引擎啟動過程中通過php_module_startup遍歷php_extension_list中在php.ini注冊的動態(tài)擴展,并依次調(diào)用對應(yīng)的Minit鉤子函數(shù),在這個過程中我們在Minit中fork出來上報進程,根據(jù)配置的url個數(shù)初始化共享內(nèi)存,并依據(jù)bkrdhash算法實現(xiàn)uri的hash存儲,同時一個hash做輸出,一個hash做存儲,并通過指針動態(tài)切換.該進程同時會監(jiān)聽主進程。
在Rinit的鉤子中,依賴于sapi_getenv和SG去獲取本次請求的參數(shù),如header和Server信息,根據(jù)uri路由,收集后存儲于trace實體中,在此鉤子中不做其他操作,保證最小粒度干擾線上的資源開銷,在Rshutdown鉤子中,統(tǒng)計響應(yīng)狀態(tài),耗時等日志信息,并存儲到對應(yīng)的hash中。
typedef struct wrm_trace_analyze {
int mutex; // 互斥量
struct timeval total_duration;
int success_times;
int failed_times;
int timeout_times;
int server_port;
char server_addr[32];
char uri[256];
} wrm_trace_analyze;
依托于配置中的上報周期,上報線程會將數(shù)據(jù)存儲的hash指針做切換,從這一刻起,另外一個空hash結(jié)構(gòu)體開始接受新數(shù)據(jù)做存儲,同時原輸出hash開始壓縮并上報數(shù)據(jù)中心服務(wù)側(cè),上報完成后等待下個周期的切換,如此循環(huán)往復(fù)。
鑒于每次的http請求都會產(chǎn)生一條日志數(shù)據(jù),如果每次都進行上報則對服務(wù)端是個很大的流量沖擊,針對這種情況我們通過合理設(shè)計本地存儲結(jié)構(gòu),實現(xiàn)時間周期內(nèi)的日志數(shù)據(jù)匯總存儲,壓縮&定期上報匯總數(shù)據(jù)。
數(shù)據(jù)實現(xiàn)hash存儲,key值采用bkrdhash算法,以質(zhì)數(shù)作為種子,每個字符串的ascii加和,保證每個字符串都參與到運算中,同時hash中只存儲有效的日志數(shù)據(jù),如http code 200/500次數(shù),時間等信息,以10000個uri舉例,只額外占用不到10M內(nèi)存,并在數(shù)據(jù)udp上報到服務(wù)側(cè)之前通過gz壓縮,保證資源的合理優(yōu)化。
我們采用的futex內(nèi)核級同步鎖.在眾多php-fpm在同一時間點寫入同一個hash的,如果采用自旋鎖+等待,在線程較多的時候其他上下文的切換的資源開銷不低,但是通過futex內(nèi)核級鎖,在通過雙向鏈表的隊列維護競爭的線程,在占用鎖資源的線程釋放資源后,會按順序從隊列中喚起等待的線程寫入。
我們采用的方案是通過監(jiān)聽進程的存儲層開辟一個共享內(nèi)存區(qū)域,分別為分為存儲區(qū)A和上報區(qū)B,在監(jiān)控服務(wù)收集的過程中所有數(shù)據(jù)沉淀在A上,等待上報周期時間點一到則會將數(shù)據(jù)寫入的指針指向B,此時B角色切換為存儲區(qū),A角色變更為上報區(qū),線程將A上的數(shù)據(jù)進行上報,上報成功后clean掉數(shù)據(jù),等待下一次的角色變更,如此循環(huán)往復(fù),實現(xiàn)線程安全的異步上報流程。
我們以php擴展為獨立載體,不依賴任何框架,支持公司內(nèi)部物理機和私有云等集群環(huán)境。業(yè)務(wù)集群需要監(jiān)控服務(wù)則可將此.so文件加載到項目extension/下目錄或者 php配置級的extension下,同時在項目中的extension.conf配置采集參數(shù)即可方便使用,也因此實現(xiàn)項目級的日志采集能力。此擴展語法同時支持PHP7.0.0以上的版本集群環(huán)境。
Restful的自動化日志監(jiān)控服務(wù),在租房業(yè)務(wù)線集群以擴展的形式已成功部署至生產(chǎn)環(huán)境,各業(yè)務(wù)線負責(zé)人可以方便的通過公司的提供的可視化工具平臺(WF manager)直觀看到所屬的接口訪問詳情,從而節(jié)省各個業(yè)務(wù)線手動開發(fā),標準不一的開發(fā)代價和維護成本。?目前租房業(yè)務(wù)線累計已有幾十個集群先后通過此擴展接入wfmanager系統(tǒng),覆蓋百余臺PHP服務(wù)器,每分鐘采集日志超上百萬次,覆蓋90%的租房業(yè)務(wù)線上流量,為服務(wù)的平穩(wěn)運行提供有力保障。通過可視化的線上接口實時訪問數(shù)據(jù),對應(yīng)服務(wù)的負責(zé)人實現(xiàn)了對所屬服務(wù)的主動關(guān)注/被動報警能力,為服務(wù)質(zhì)量和穩(wěn)定性提供了有力的支持,具體體現(xiàn)在以下兩個方面:
1. 在工程效率方面,過往線上出現(xiàn)接口訪問超時現(xiàn)象到問題解決的時間跨度周期往往超過1天,通過此擴展接入日志采集能力后,實現(xiàn)了線上的訪問實時監(jiān)控預(yù)警,從問題出現(xiàn)到解決的時間跨度也降低為分鐘級別,如 一些APP端的詳情頁在優(yōu)化之前接口加載時長達到300ms以上,接入日志監(jiān)控擴展后清晰看到線上的真實耗時,對應(yīng)同學(xué)收到預(yù)警后,經(jīng)過幾輪實時技術(shù)優(yōu)化對比,已成功將耗時降低為100ms以下。
2. 在數(shù)據(jù)分析維度,過往分析日志從單機awk統(tǒng)計到現(xiàn)在集群整體視角,粒度甚至細分至單機uri的級別,直觀監(jiān)測到實時訪問數(shù)據(jù),實現(xiàn)了同比,環(huán)比的流量波動分析,精準掌握產(chǎn)品的線上的訪問流量,為保證服務(wù)可用性的增擴容以及優(yōu)化提供有力決策支持。?
文章轉(zhuǎn)自微信公眾號@58技術(shù)