摘要:引言作為由騰訊公司開源的優秀框架與服務部署運維解決方案,被閱文集團引入了實際實踐中,同時閱文集團對在語言層面進行了能力的補全,令如虎添翼。作為騰訊公司的優秀框架與服務部署運維解決方案,可以滿足上述的所有需求。
引言梁晨(Ted),任職閱文集團技術中心,負責起點中文網的WEB后臺開發工作。曾負責騰訊上海企業產品部營銷QQWeb后臺開發、QQ公眾號Web后臺開發,對大型網站技術架構,有自己的經驗和見解。騰訊開源項目TSF2.0框架開發者,騰訊開源組件Tars-PHP開發者,也曾是騰訊公司多個PHP擴展組件的開發者與維護者。
TARS作為由騰訊公司開源的優秀RPC框架與服務部署運維解決方案,被閱文集團引入了實際實踐中,同時閱文集團對TARS在PHP語言層面進行了能力的補全,令TARS如虎添翼。TARS-PHP的解決方案兼具簡單高效、接口維護方便容易擴展、代碼自動生成,以及集成尋址、服務發現、監控、上報等功能。經歷了閱文集團線上業務的考驗與洗禮,充分證明了該解決方案的優勢。
項目地址:https://github.com/Tencent/Ta...
"PHP是世界上最好的語言"眾所周知,在PHP誕生之初,就是WEB站點的開發而生。但是一直以來,都無法擺脫弱類型、腳本語言的性能之殤的帽子。隨著互聯網行業的不斷發展,以及用戶需求和基礎架構的不斷變化,PHP語言本身也一直在發展。無論是SWOOLE的出現,還是PHP7對性能的提升,都豐富和助力了PHP本身的應用。
相信大家在開發中也會發現,作為經常處在WEB中間層的PHP,其實有很多的痛點。既要接收前端的HTTP請求,又要調用各式各樣的后臺服務與存儲服務,常常成為一個站點的性能瓶頸。其中HTTP協議的過分冗余以及上層封裝帶來的損耗,就是一個比較突出的問題。
開發者不但要應對使用同步的HTTP的調用庫所帶來的吞吐量的下降,還要忍受HTTP協議本身,以及JSON、XML協議在信息傳輸上的低效率。為了解決這一問題,一套在TCP協議層的,使用簡單的二進制協議。才能保證業務用更少的傳輸帶寬,承載更多的傳輸內容,從而提高吞吐量和WEB服務伺服能力。
同時,在實際開發的層面上,PHP邏輯層與后臺服務之間通信協議的維護成本較高。同時,后臺服務側新增或修改接口字段,往往調用側也要配合修改,很多時候無法保證接口的完全兼容而引發線上的運營問題。因此,這種二進制協議又要做到接口方便維護,同時又容易擴展。
除此之外,從開發效率上而言,原本的開發中總是包含大量的重復的,但又不得不去做的工作內容。因為每一次新協議的開發,代碼很難復用,JSON和XML也并不允許你共用部分數據。同時一個很現實的問題是,不同HTTP接口的提供方,往往會視自己的心情和習慣來定義接口。
一個常見的例子就是對返回碼的定義,有些人叫ret,有些人叫code,還有些人就叫r,簡直是無所不包。因此這類重復無趣的開發工作,給調用方的開發同學帶來了極大的生理和心理負擔。基于這種需求,一種服務端和客戶端都能夠根據協議和接口自動生成調用代碼,保證聯調通暢的解決方案必不可少。
再者,調用方對后端服務的發現和調用的上報與監控,也是一個老生常談的問題。后端服務如何被發現,后端的接口如何被發現,這都是調用方真真切切想知道的。同時,調用方非常有必要對后端服務的調用情況進行上報到中央服務器,中央服務器再根據收集上來的信息,對后端服務的負載進行動態的調整,保證服務的高可用。要實現這樣的需求,必須引入一種集成了監控、主控尋址、上報通道、負載均衡功能的解決方案。
Tars作為騰訊公司的優秀RPC框架與服務部署運維解決方案,可以滿足上述的所有需求。通過引入Tars-PHP的全套解決方案,開發者既可以使用二進制的Tars協議,大大壓縮了服務請求的流量。同時也能夠借助Tars協議解析的PHP擴展,提高了打包解包的性能進而提升了單進程的任務處理能力。再次,自動生成代碼的工具也能夠提升開發者的效率。
Tars-PHP解決方案Tars-PHP的開源方案,首先從二進制的協議說起:
二進制協議HTTP協議可能是在應用層上使用最為廣泛的協議了。現有HTTP的版本主要是1.0和1.1版本。它在TCP協議的基礎上做了十分簡潔的應用層協議封裝,純文本的內容,以及Header和Body的區分。都使得這種協議的使用和理解十分的方便。但是不可避免的,使用和閱讀的簡單意味著信息的冗余,為了傳輸少量的內容,往往需要耗費大量的流量。
另外兩個比較熟知的協議,就是JSON和XML了,這兩位在API交互常用的協議中不分上下,可讀性強、容易理解、語言客戶端支持豐富、協議表述能力突出,都是兩者的優勢所在。先看看同樣一段信息,兩者需要的數據量。
假定有一所學校,一個學生,如果用JSON標識的話,如下所示:
{ "school": { "student":{ "name":"ted", "age":18, "degree":"master" } } }
很簡單的結構,共需要65個字符來表述。而如果換成XML:
ted 18 master
則一共需要92個字符。從信息學的角度而言,信息熵明顯就是太低了。所以為了實現通信的更高性能和更少帶寬的使用,二進制協議的引入勢在必行。
Tars協議作為一個二進制的協議,相比于上述兩個協議的優勢不言自明。從上文中的JSON和XML中發現其靈活性,也就是沒有指定字段的類型。但是不可避免的,這種靈活帶來了性能的大損失。因此Tars定義了八種基本的數據類型,通過對不同的數據類型進行編碼優化:
bool、byte、short、int、long、float、double 、string
而同時為了滿足業務需求,擴展出了struct(包含任意字段)、vector(數組)、map(key-value結構)這三種可以嵌套數據,豐富協議表現力的復雜類型。
按照上文的表現結構,幾個struct就可以完成。
首先是student結構體:
struct student { 0 required string name; // tag為0,type為string,實際數據為ted,共5個字節 1 required byte age; // tag為1,type為short,實際數據為18, 共2個字節 2 required string degree; // tag為2,type為string,實際數據為master,共7個字節 }
從注釋中可以看到,三個字段需要的字節數為14,再加上結構體的開始和結構體結束的標識共2個字節,一共只需要16個字節而已。相比之下,這僅僅是JSON的1/4,是XML協議標識同樣信息的1/5,高下立判. 巧妙地用協議強約定換傳輸可讀性,這就是高信息熵的二進制協議的訣竅。
為了使得PHP能夠充分與Tars結合,必須使其具備作為客戶端和作為服務端兩個方面的能力。
Tars-PHP的客戶端作為客戶端而言,要能夠滿足快速開發的需求,也要能夠與PHP現有的常見使用方式相結合,同時還要給出遠程調用的實例。基于這些需求,客戶端方案中實現了如下的特性:
實現了用TUP協議進行打包解包、編碼解碼的PHP擴展及相應的測試用例;
實現了從Tars協議文件生成對應PHP類文件的tars2php工具;
實現了包含網絡庫的二次封裝,以及遠程調用的代碼示例;
作為客戶端實現的最核心一步,就是對TUP協議的支持。TUP協議是在Tars協議的上層,通過固定的數據結構封裝一些收發包必須的信息,如返回值、輸入輸出參數、包本身的狀態、包計數等,來給非Tars原生客戶端與Tars服務端進行通信的協議。Tars-PHP在支持TUP協議的方案中,選擇了使用PHP擴展作為實現方式。
PHP語言本身被詬病最多的,就是針對CPU密集型的運算的低效率。由于并不十分高效的ZEND虛擬機、松散的數據結構和弱類型的存在,使得打包、解包這類CPU密集型的效率低下。因此,PHP擴展應運而生。通過引入高性能的C/C++類庫和一些原生的C/C++實現,使得PHP在性能處理方面迎頭趕上。這也就是以擴展的方式實現打包解包主邏輯的初衷。
首先來看看PHP5x語言的結構:
最底層的Server API用來PHP與Webserver通信,這個主要是之前與APACHE配合需要使用的。在其左上的PHPCORE層,是為了提供最基本的文件和網絡操作的能力。而右上的ZEND,則是用來把PHP的腳本語言編譯成機器碼的工具。最上面就是擴展層了,這層會充分利用ZEND的API和PHPCORE的能力,直接寫出ZEND能夠高效執行和理解的代碼,省去了PHP腳本編譯為機器碼的過程,從而大大的提高執行的效率。
如果要設計這個擴展,必須要將上文中Tars的數據結構通過C語言的方式加以表達,同時設計出基于這套數據結構的編碼器與解碼器。另一個需要考慮的方面是,必須要使得在PHP層面盡可能的簡單、易用,這就對擴展的設計提出了比較高的挑戰。一方面要兼顧性能,另一方面,要將Tars協議中的Struct,進行了PHP中的Class的表達:
從圖中可以清晰的看到,結構體SimpleStruct被分解成了三個部分:
TAG部分
成員變量部分
變量描述的fields
TAG部分至關重要,這部分用來代表Struct中每個元素的TAG值。這也是實際進行TUP編碼和解碼的時候,二進制包里面最終包含的內容。為什么要有TAG?這是因為相比于JSON里面對字段的文本性質的描述,TAG本身更節省空間。
第二部分則是類的成員變量,這部分成員變量和Tars協議的Struct中的變量一一對應。這是為了承載對應變量的實際值而存在的。借此才能對真正的數據進行打包和解包。
為了在TAG和變量之間搭起一座橋梁,就有了第三部分:Fields部分。這部分是TAG與其對應的變量屬性的一個映射。包含了變量的名稱、變量是否必填以及變量的類型。通過這些信息,一方面實現了對Tars協議的二進制編碼,也實現了解碼時候的映射。可謂一舉兩得。
那么經過復雜的擴展設計與實現,有必要將擴展實現的打包解包性能和原生PHP實現的打包解包性能進行比對。從下面的表格中可以非常明顯的看出擴展實現擁有性能上面的絕對優勢:
方式/100次 | tars復雜度 | 打包時間(ms) | 打包耗時倍數 | 解包時間(ms) | 解包耗時倍數 |
---|---|---|---|---|---|
擴展 | 簡單 | 0.69 | 1 | 1.18 | 1 |
php原生 | 簡單 | 11.25 | 16 | 16.28 | 13 |
擴展 | 復雜 | 1.17 | 1 | 1.55 | 1 |
php原生 | 復雜 | 14.5 | 12 | 15.1 | 10 |
從這個表格中可以非常清晰的看到,無論是簡單的Tars協議,還是復雜的Tars協議,使用擴展進行打包解包都比原生PHP的性能提高十倍以上。當遇到復雜的業務邏輯,需要調用大量的使用Tars協議的后臺服務的時候,這種效率的提升會讓服務的吞吐量上一個數量級。
開發者在完成擴展的編譯工作之后,就可以非常方便的使用TUP協議進行打包,解包與編碼解碼的工作了。
// 針對基本類型的打包和解包的方法,輸出二進制buf $buf = TASAPI::put*($name, $value); $value = TUPAPI::get*($name, $buf); // 針對Struct,傳輸對象,返回結果的時候,以數組的方式返回,其元素與類的成員變量一一對應 $buf = TUPAPI::putStruct($name, $clazz); $result = TUPAPI::getStruct($name, $clazz, $buf); // 針對Vector,傳入完成pushBack的Vector $buf = TUPAPI::putVector($name, TARS_Vector $clazz); $value = TUPAPI::getVector($name, TARS_Vector $clazz, $buf); // 針對Map,傳入完成pushBack的Map $buf = TUPAPI::putMap($name, TARS_Map $clazz); $value = TUPAPI::getMap($name, TARS_Map $clazz, $buf); // 需要將上述打好包的數據放在一起用來編碼 $inbuf_arr[$name] = $buf; // 進行tup協議的編碼,返回結果可以用來傳輸、持久化 $reqBuffer = TUPAPI::encode( $iVersion=3, $iRequestId, $servantName, $funcName, $cPacketType=0, $iMessageType=0, $iTimeout, $context=[], $statuses=[], $inbuf_arr); // 進行tup協議的解碼 $ret = TUPAPI::decode($respBuffer); $code = $ret["code"]; $msg = $ret["msg"]; $buf = $ret["sBuffer"];
為了方便開發者擴展使用中經常遇到的無法找到具體函數和參數的問題,同時提供了tars-ide-helper:
以PHPSTORM為例,只需要導入到相應的INCLUDE路徑中,就可以實現自動提示了:
除了打包解包的能力,Tars-PHP同時也提供了網絡收發的能力,網絡收發主要實現了以下幾個點:
TarsAssistant.php文件:通過COMPOSER加載,底層內置SOCKET原生網絡層收發包實現;
根據Interface自動生成PHP的Class,與TarsAssistant無縫結合
提供Exception等容錯處理;
一旦完成了代碼的自動生成之后,使用者即可通過如下代碼,方便的進行遠程Tars服務調用:
require_once "./vendor/autoload.php"; $ip = "";// taf服務ip $port = 0;// taf服務端口 $servant = new AppServerServantservant($ip,$port); $in1 = "test"; $ss1 = new SimpleStruct(); $ss1->id = 1; $ss1->count = 2; $ss1->page = 3; try { $intVal = $servant->singleParam($in1,$ss1,$out1); } catch(phptarsTarsException $e) { // 錯誤處理 }Tars-PHP的服務端
除了建設Tars-PHP作為客戶端的能力之外,服務端的能力同樣是必不可少的。為了能夠滿足不同業務場景下的需求,Tars-PHP在服務端主要會關注兩類服務。
第一類是HTTP的服務,會以SWOOLE2.0為網絡收發的基礎,實現一套高性能、簡潔好用的面向WEB服務的框架。這套框架會支持基本的 路由、中間件、MVC架構等常見的WEB框架特性。同時也會集成Redis、Mysql、Http、Multicall、Tars等常見的客戶端,方便WEB服務再去調用后臺服務。更重要的是,接入到Tars平臺中,使得服務可監控,可重啟,享受Tars運維平臺帶來的一站式便利。現在框架的第一個版本已經實現,并在閱文集團內部上線使用,測試成熟后,會及時進行開源。
第二類則是TCP的服務,同樣底層依賴于SWOOLE2.0,但是協議從HTTP換成了對TUP和Tars的支持。框架實現上而言,會與JAVA、C++的服務端保持一致,底層集成網絡能力,使用者只需關心服務名稱以及接口參數和自己的業務處理邏輯而已。當然,這個服務肯定也是要與Tars運維平臺相結合的。現在框架對TUP協議支持的第一個版本已經完成,后續也會在完成Tars協議的底層支持之后,在業務上進行使用和驗證。
業務實踐閱文集團在進行后臺服務治理與改造的過程中,使用了Tars-PHP的解決方案。一方面,所有WEB后臺與后臺服務的接口,全部從原有的HTTP接口,切換為了基于Tars協議的TCP網絡傳輸。依賴于Tars-PHP的自動代碼生成,開發效率提升巨大,保證了項目的順利按時上線。同時,這套基于PHP擴展的方案,也保證了代碼執行效率的高效,單個請求的處理時間,相比于原有的HTTP接口調用,得到了顯著的縮短。
另一方面,由于使用的WEB后臺服務是常駐內存的,基于SWOOLE的實現。所以在發布、啟動、監控等方面與原有PHP中固有的Apache和PHP-FPM的方式都不相同。因此,正如上文中所說,服務接入Tars平臺,享受其監控、保活、日志等一系列的功能,會大大提高服務本身的運維和擴容的便利性。如今在其線上服務中,超過十個服務已經切入并穩定運行了接入到Tars平臺的HTTP服務。這些服務的發布、擴容和運維完全依賴Tars平臺,十分便利。
除去對Tars平臺運維的使用,閱文WEB后臺側同樣在服務發現上,有一套方案。
對于遠程服務的地址管理,最差的方案就是將其寫入本地文件中。這種方案無法應對快速縮擴容以及服務器下線的需求,會給后續的運維帶來很大的工作量。
稍微好一些的方案是本地存儲虛擬IP,那么每次只需要調整虛擬IP,就可以實現服務地址的自動映射和變化。但是這意味著對要調用的每一個后臺服務,都需要存儲其對應的虛擬IP、HOST信息、接口信息等一系列的信息,同樣維護成本很高。
而更加通用的方案,則是提供服務的統一配置中心,每次需要調用后臺服務的時候,就從配置中心根據唯一的標識拉取出服務最新的地址。這樣一方面能夠做到縮擴容對業務的無感知,另一方面配置中心也能夠通過服務的尋址情況,給每個客戶端分配最適合它的服務機器地址,比如機房或者SET就近分配等等。本地的服務只需要提供兩個能力,第一個是能夠調用定期的尋址服務,并存入本機的存儲中,保證尋址的速度。第二個則是能夠接收配置中心下發的命令,更新特定服務的地址。能做到這兩點,就能夠實現高效的尋址和可靠的尋址了。
在實際使用中,結合實際業務情況,一方面每分鐘向主控請求一次服務的地址,通過輪詢的方式獲取一個可用的服務地址,再放入本地的高速共享內存,方便在這一分鐘之內重復的讀取。另一方面在每次服務調用的時候,都自動在底層集成對服務調用情況的耗時、成功率的上報。在雙管齊下的作用之下,對遠程服務的調用不再像過去那樣難以維護、難以開發、難以監控,而是清晰可見高效的被管理。
結語從開發效率上而言,使用Tars-PHP擺脫了過分冗余的業務代碼,以自動生成的方式提高代碼開發自動化程度。
從性能方面而言,Tars-PHP方案通過引入擴展,做到了性能的大幅度提升,讓性能不再成為PHP“之殤”。
從易用性而言,通過提供TarsAssistant的網絡收發組件,使得收發包無需多帶帶實現。后面也會引入更高性能的Swoole作為socket收發的利器,進一步提高網絡性能。
后續,Tars-PHP的SERVER側方案也會盡快開源,從而能夠提供一套包含客戶端與服務端的完整解決方案。這一整套的WEB后臺的Tars-PHP開發體系,能夠真正做到了高性能、高效率與高可用。而閱文集團也會繼續與騰訊在Tars-PHP技術方案上深度合作與實踐。歡迎開發者試用!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/26024.html
摘要:月日,在上海舉行的第六屆中國開發者大會上,騰訊開源項目首次全面發布版本,閱文集團高級開發工程師梁晨對如何通過構建高性能框架做了經驗分享。騰訊開源項目貢獻者,騰訊開發組成員,對于構建高性能后臺微服務治理有豐富的經驗。 5月19日,在上海舉行的第六屆中國PHP開發者大會(PHPCon)上,騰訊開源項目TARS首次全面發布PHP版本,閱文集團高級開發工程師梁晨(Ted)對PHP如何通過TAR...
摘要:什么是是騰訊從年到今天一直在使用的后臺邏輯層統一應用框架的開源版本,目前支持和三種語言。目前該框架在騰訊內部的各大核心業務都在使用,頗受歡迎,基于該框架部署運行的服務節點規模達到上萬個。 | 博客文章 你所不知的TARS,卻幫閱文集團完成技術架構變革!——TARS開啟閱文集團技術架構變革之門 作者簡介|歐樑后端研發架構師,現任職于閱文集團技術部基礎服務研發組,一直致力于Java應用架構...
摘要:年月日,在上海舉行的第六屆中國開發者大會上,騰訊開源項目首次全面發布版本,閱文集團高級開發工程師梁晨對如何通過構建高性能框架做了經驗分享。分享內容作為騰訊開源的框架,在發布之后即受到開源領域的關注。閱文集團本身也有一塊新的業務在使用。 2018年5月19日,在上海舉行的第六屆中國PHP開發者大會(PHPCon)上,騰訊開源項目TARS首次全面發布PHP版本,閱文集團高級開發工程師梁晨對...
摘要:會議期間騰訊副總裁曾宇,閱文集團副總裁傅徐軍等嘉賓共同啟動合作發布儀式,并進行了圓桌會議,對進行了詳細的探討發言。會上,騰訊公司副總裁曾宇談到了騰訊整體的開源策略,并表示技術必須產生價值,開源需要攜手發展。 近日,由中國工信部指導,信通院主辦的云計算開源產業大會在國家會議中心舉行。大會邀請了行業內多位重磅人物與共同探討、交流云計算開源技術及產業化經驗,探索開源技術創新的發展途徑,也開啟...
閱讀 2386·2021-09-22 16:01
閱讀 3153·2021-09-22 15:41
閱讀 1171·2021-08-30 09:48
閱讀 490·2019-08-30 15:52
閱讀 3324·2019-08-30 13:57
閱讀 1713·2019-08-30 13:55
閱讀 3649·2019-08-30 11:25
閱讀 757·2019-08-29 17:25