快速入門SRPC

1412發表於2023-03-26
開源2年半了,一直都還沒給SRPC系統地寫過什麼文章。
趁著最近釋出了srpc構建小工具,也給SRPC寫幾篇交流學習文件,
希望單獨的每一篇都能讓不同程度的小夥伴有所收穫~~~

1. 從srpc小工具開始

最近給SRPC框架做了一個小工具用於快速構建Workflow和SRPC專案的腳手架,旨在降低專案使用門檻,解決大部分零基礎開發者第一次面對cmake檔案編寫、lib的依賴編譯與執行環境等容易遇到的問題。

srpc小工具,讓開發者的三個步驟:構建 - 編譯 - 執行,都變得更簡單(叉腰!

SRPC地址:https://github.com/sogou/srpc

另外,懶了好久沒po文,新小夥伴可能比較多,以下補充一些可以跳過的背景知識。

SRPC是一個輕量級、企業級、效能優異的RPC框架,程式碼結構精巧解耦合,跟隨原始碼看請求過程一氣呵成,非常適合用來學習RPC架構,部署使用也都比較方便。

SRPC又是基於Workflow開發的,Workflow目前已經是一個萬星專案、成為Debian / Ubuntu Linux / Fedora等系統的自帶安裝包,也獲得了大家還不錯的口碑,所以就不多介紹了。等這列文章完結之後,我會再開展Workflow的學習系列,如果對底層網路模型、計算排程做法、任務流設計等感興趣的小夥伴,需要再給一丟丟耐心等待~

Workflow地址:https://github.com/sogou/workflow

2. 一行命令構建起你的專案

2.1 原始碼位置

我們把上述的專案clone下來,並開啟tools目錄,就可以編譯出我們的srpc小工具。工具名字也叫srpc,但是是小寫的~

git clone https://github.com/sogou/srpc.git
cd srpc/tools && make

這個小工具和SRPC框架目前還沒有關係,所以即使本地沒有安裝SRPC所需要的protobuf或者不加--recursive拉submodule下來,也依然可以編譯。唯一需要的是cmake 3.6及以上的版本。

2.2 執行工具

我們先把這個srpc小工具執行起來,可以看到它第二個引數COMMAND:表示支援什麼命令

./srpc
Description:
    Simple generator for building Workflow and SRPC projects.

Usage:
    ./srpc <COMMAND> <PROJECT_NAME> [FLAGS]

Available Commands:
    http        - create project with both client and server
    redis       - create project with both client and server
    rpc          - create project with both client and server
    proxy      - create proxy for some client and server protocol
    file           - create project with asynchronous file service
    compute - create project with asynchronous computing service

這些COMMAND包括了我們最常用的場景,適合入門瞭解伺服器程式設計最簡單的內容。

2.3 一行命令構建專案

第三個引數是專案名,我們先用一行簡單的命令,構建出一個Http伺服器與客戶端。

./srpc http my_project
Success:
      make project path " my_project/ " done.

Commands:
      cd my_project/
      make -j

Execute:
      ./server
      ./client

可以看到提示Success!

2.4 第一個專案的編譯和執行

我們按照上述的提示看到:my_project目錄已經在本地目錄下建立,並給出了:

  • 編譯的命令:make
  • 執行的命令:分別在兩個終端上執行./server 和 ./client
cd my_project
make

執行ls -all 一下可以看到,兩個可執行檔案已經編譯出來了。我們分別在兩個終端執行./server./client

./server 
Http server started, port 8080
http server get request_uri: /client_request
peer address: 127.0.0.1:65313, seq: 0.

client執行起來後會給server發一個請求,然後server會列印出上面顯示的最後兩行,然後client收到回覆之後也會列印下面的兩行:

./client 
Http client state = 0 error = 0
<html>Hello from server!</html>

2.5 模組依賴,是C++專案的第一道門檻

剛才git clone專案時沒有加--recursive拉取依賴的submodule,且srpc的lib是還沒有沒有編譯的,那麼其實工具都自動會幫做這些初始化的工作

當然,目前C++跟GO等其他語言比起來在構建方面還是薄弱了一點。如果大家還沒有安裝protobuf,或者系統的版本太舊、導致編譯SRPC時所依賴的protobuf版本與連結時不一樣,那麼可以先使用原始碼編譯protobuf

這裡找了一個不太新也不太舊的版本,供需要安裝protobuf的小夥伴參考:

git clone -b 3.20.x https://github.com/protocolbuffers/protobuf.git protobuf.3.20
cd protobuf.3.20
sh autogen.sh
./configure
make -j4
make install

然後我們就可以愉快再試一下上述步驟了~

3. 一個腳手架專案包含了什麼?

我們執行tree命令,檢視這個專案裡的檔案結構。

需要我們關注的有這些:

3.1 編譯檔案

腳手架小工具目前還是使用cmake進行編譯,後續計劃支援bazel和xmake。

GNUmakefile包了一層cmake命令,讓我們可以執行make就編譯出專案,這個檔案我們不需要關心。

開啟CMakeLists.txt,可以看到一共32行,包括了:

  1. 尋找依賴路徑的寫法
  2. include和link的寫法
  3. 編出執行檔案

開發者可以根據裡邊的註釋自行修改,即使不常用C++的開發者也可以邊試邊學

3.2 client

client會讀取client.conf作為它的配置檔案,主要是指定要訪問的目標是什麼。

我們開啟client_main.cc,可以看到腳手架預設生成的client只有60多行,一共做了3件事:

int main()
{
    // 1. 初始化,這個實現也在原始碼中,主要是呼叫config.load("./client.conf")
    init();

    std::string url = std::string("http://") + config.client_host() +
                      std::string(":") + std::to_string(config.client_port());
 
    // 2. 構造一個http task並且填回撥函式
    WFHttpTask *task = WFTaskFactory::create_http_task(url,                        
                                                        config.redirect_max(),  
                                                        config.retry_max(),        
                                                        callback);
    // 3. 把task執行起來
    task->start();                                                                 

    wait_group.wait();
    return 0;
}

可以看到,這個和workflow的tutorial中的例子是一樣的,需要填的callback函式也在檔案中。

3.4 server

我們開啟server_main.cc,50多行的程式碼,也是做了3件事,可以看到和上面的client是非常對稱的

int main()
{
    // 1. 初始化,這個實現也在原始碼中,主要是呼叫config.load(“./server.conf")
    init(); 

    // 2. 造一個server,填好處理函式
    WFHttpServer server(process);                                                  

    // 3. 把server執行起來
    if (server.start(config.server_port()) == 0)                                   
    {
        fprintf(stderr, "Http server started, port %u\n", config.server_port());
        wait_group.wait();
        server.stop();
    }
    else
        perror("server start");

    return 0;
}

process函式也在原始碼中,開發者可以嘗試修改,進行不同的行為處理。示例中的行為就是回覆一個 " Hello from server! "

3.5 配置檔案

配置解析並不是Workflow和SRPC專案自帶的,但是腳手架專案增加了這個功能。

我們目前使用的配置檔案都是json格式,和配置解析相關的都放到了config目錄中。除了client.confserver.conf以外,我們還多加了一份full.conf,用來指引Workflow和SRPC目前支援的配置項,開發者可以通配置檔案,快速瞭解我們還可以用什麼功能。

比如框架的全域性配置:

{                                                                                  
  "server":                                                                        
  {
    "port": 8080                                                                   
  },
                                                                                   
  "client":                                                                        
  {
    "remote_host": "127.0.0.1",
    "remote_port": 8080,
    "retry_max": 1,
  },

  "global":
  {
    "poller_threads": 4,
    "handler_threads": 20
  }
}

熟悉的開發者可能接觸過Workflowupstream,以及tracemetrics等監控資料的上報外掛,這些都可以在配置檔案中指定並一鍵載入,幫開發者接管外部生態,真正實現腳手架的能力。

4. 命令大全

經過以上介紹,應該可以基本掌握怎麼快速構建和執行一個自己的小專案。接下來我們進一步解鎖這個srpc小工具,每個COMMAND都是一個二級命令

4.1 rpc命令

構建一個以protobuf或者thrift作為IDL的多協議RPC專案。

如果先前沒有了解過SRPC的小夥伴,有空可以圍觀一下這份wiki:SRPC架構介紹 - Sogou基於Workflow的自研RPC框架,也可以這裡用一句話簡述一下:

SRPC框架支援:

  • 多種協議
  • 多種IDL
  • 多種資料格式
  • 多種壓縮演算法

我們的client和server只需要保證以同樣的協議進行通訊,而其餘的東西交給SPRC框架幫你處理就好,最終開發者接觸到的就是我們的IDL所約定的介面,比如在xxx.proto檔案中長這樣:

service rpc_test {                                                                 
    rpc Echo(EchoRequest) returns (EchoResponse);                                  
};

其中,支援的RPC協議包括:SRPC、SRPCHttp、BRPC、TRPC、TRPCHttp、Thrift、ThriftHttp

這些東西都可以在構建時透過引數指定。

我們執行./srpc rpc,就可以看到rpc命令支援的引數:

我們嘗試以預設方式構建一個RPC專案。也可以使用-f指定IDL檔案進行構建,這會使用srpc_generator去進行程式碼生成

./srpc rpc rpc_project

開啟之後,可以看到和Http相比,有如下區別:

  1. 多了一個rpc_project.proto
  2. server_main.cc和client_main.cc分別變成了SRPCServerSRPCClient
  3. CMakeLists.txt也變複雜了,因為需要依賴protobuf和snappy等壓縮庫;

但我們依然可以透過make把專案編譯出來。執行方式與前面類似,不再贅述。

4.2 redis命令

這個命令主要用於構建redis協議的server和client,由於Workflow的協議對server和client來說都是對等的,因此基於Workflow實現的redis server依然非常簡潔高效。

這個例子中,client發出的請求是set k1 v1,server收到任何內容都回復一個OK。並且client.conf中增加了使用者名稱和密碼的項,開發者可以透過修改配置,用這個client訪問其他任意的redis server。

4.3 proxy : 代理伺服器

代理伺服器顧名思義,就是可以多構建一個proxy,我們可以用client去訪問proxy,並由proxy去轉發給server,這中間proxy就可以做很多事情,包括:更改協議、內容校驗等等。

一個常見的場景是,我們的現有業務是客戶端發出TRPC協議,而需要訪問SRPC協議的伺服器時,則可以構建出一個TRPC-SRPC的proxy,並且讓大家使用統一的proto檔案約定好請求,則proxy就可以直接做轉發。

我們執行如下命令,用-c指定client端的協議,用-s指定server端的協議:

./srpc proxy proxy_project -c trpc -s srpc

然後還是按照前面所述的編譯和執行。這裡我們分別執行起來./server./proxy./client

proxy_main.cc的實現,是起了一個TRPCServer,並使用SRPCClient去轉發請求。感興趣的小夥伴可以圍觀一下,其實SRPC專案的tutorial裡也已經有這樣的例子了:tutorial-15-srpc_pb_proxy.cc

4.4 file : 檔案伺服器

檔案伺服器透過非同步IO讀取,也是我們常用的功能,這裡不再贅述,對實現感興趣的小夥伴歡迎檢視原先的一篇文章:《Workflow程式設計小示例4: 轉發伺服器與series上下文的使用》

我們透過./srpc file file_project構建一下專案,我們可以透過curl命令去讀取想要的檔案,例如curl localhost:8080/index.html 就可以讀取到指定root目錄下的index.html檔案。

可以看到,多了一個html的目錄,裡邊放了index.html, 404.hmtl50x.html。如果使用過其他Http伺服器的小夥伴應該不陌生,這是常見的用法。

.
├── CMakeLists.txt
├── GNUmakefile
├── config
│   ├── Json.cc
│   ├── Json.h
│   ├── config.cc
│   └── config.h
├── file_service.cc
├── file_service.h
├── html
│   ├── 404.html
│   ├── 50x.html
│   └── index.html
├── server.conf
└── server_main.cc

3 directories, 13 files

我們還可以透過配置檔案去指定具體錯誤碼對應的錯誤頁面,而錯誤頁面和其他檔案一樣,都是透過非同步IO的方式讀取,不會阻塞server當前的處理執行緒。

熟悉的error_page,它來了:

{     
  "server":     
  {     
    "port": 8080,     
    "root": "./html/",     
    "error_page" : [     
      {     
        "error" : [ 404 ],     
        "page" : "404.html"     
      },     
      {     
        "error" : [ 500, 502, 503, 504],     
        "page" : "50x.html"     
      }     
    ]     
  }     
}

4.5 compute : 計算伺服器

計算伺服器也是透過go_task發起計算任務,不會阻塞當前執行緒。實現原理歡迎參考:《WF程式設計小示例6: 計算型伺服器與計算任務》

5. 其他

srpc小工具的基本用法就介紹完了,但是由於它剛剛面世,之後會支援命令還會更多,支援的配置也會更多,比如error_page這種大家習慣的配置用法,22同學都會想想怎麼加上~

希望這個小工具可以減少開發者第一次接觸專案時,“構建 - 編譯 - 執行”所面臨的困難,而SRPC專案之後也將致力於降低開發者使用門檻,包括最佳化依賴庫和submodule提供更多編譯方式支援更多好用的生態外掛等等。

當然這系列的學習文章也是降低使用門檻陪伴小夥伴們學習程式碼獲取大家反饋促進交流的重要一環,之後爭取周更,把這系列的坑填完!所以想要看什麼內容或者對srpc小工具有什麼建議要提的都得趕緊了~

最後附上github上的文件:https://github.com/sogou/srpc/blob/master/tools/README.md