小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Thrift RPC 使用指南實(shí)戰(zhàn)(附golang&PHP代碼)

 quasiceo 2017-09-15

Thrift RPC 框架指南

認(rèn)識(shí)Thrift框架

thrift是一個(gè)軟件框架,用來(lái)進(jìn)行可擴(kuò)展且跨語(yǔ)言的服務(wù)的開(kāi)發(fā)。它結(jié)合了功能強(qiáng)大的軟件堆棧和代碼生成引擎,以構(gòu)建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 這些編程語(yǔ)言間無(wú)縫結(jié)合的、高效的服務(wù)。

  • thrift最初由facebook開(kāi)發(fā),07年四月開(kāi)放源碼,08年5月進(jìn)入apache孵化器。
  • thrift允許定義一個(gè)簡(jiǎn)單的定義文件中的數(shù)據(jù)類型和服務(wù)接口,以作為輸入文件,編譯器生成代碼用來(lái)方便地生成RPC客戶端和服務(wù)器通信的無(wú)縫跨編程語(yǔ)言。
  • 類似Thrift的工具,還有Avro、protocol buffer,但相對(duì)于Thrift來(lái)講,都沒(méi)有Thrift支持全面和使用廣泛。

Thrift自下到上可以分為4層

Server(single-threaded, event-driven etc)
服務(wù)器進(jìn)程調(diào)度
Processor(compiler generated)
RPC接口處理函數(shù)分發(fā),IDL定義接口的實(shí)現(xiàn)將掛接到這里面
Protocol (JSON, compact etc)
協(xié)議
Transport(raw TCP, HTTP etc)
網(wǎng)絡(luò)傳輸

Thrift實(shí)際上是實(shí)現(xiàn)了C/S模式,通過(guò)代碼生成工具將接口定義文件生成服務(wù)器端和客戶端代碼(可以為不同語(yǔ)言),從而實(shí)現(xiàn)服務(wù)端和客戶端跨語(yǔ)言的支持。用戶在Thirft描述文件中聲明自己的服務(wù),這些服務(wù)經(jīng)過(guò)編譯后會(huì)生成相應(yīng)語(yǔ)言的代碼文件,然后用戶實(shí)現(xiàn)服務(wù)(客戶端調(diào)用服務(wù),服務(wù)器端提服務(wù))便可以了。其中protocol(協(xié)議層, 定義數(shù)據(jù)傳輸格式,可以為二進(jìn)制或者XML等)和transport(傳輸層,定義數(shù)據(jù)傳輸方式,可以為T(mén)CP/IP傳輸,內(nèi)存共享或者文件共享等)被用作運(yùn)行時(shí)庫(kù)。

Thrift支持的傳輸及服務(wù)模型

支持的傳輸格式:

參數(shù) 描述
TBinaryProtocol 二進(jìn)制格式
TCompactProtocol 壓縮格式
TJSONProtocol JSON格式
TSimpleJSONProtocol 提供JSON只寫(xiě)協(xié)議, 生成的文件很容易通過(guò)腳本語(yǔ)言解析。
TDebugProtocol 使用易懂的可讀的文本格式,以便于debug

支持的數(shù)據(jù)傳輸方式:

參數(shù) 描述
TSocket 阻塞式socker
TFramedTransport 以frame為單位進(jìn)行傳輸,非阻塞式服務(wù)中使用。
TFileTransport 以文件形式進(jìn)行傳輸。
TMemoryTransport 將內(nèi)存用于I/O. java實(shí)現(xiàn)時(shí)內(nèi)部實(shí)際使用了簡(jiǎn)單的ByteArrayOutputStream。
TZlibTransport 使用zlib進(jìn)行壓縮, 與其他傳輸方式聯(lián)合使用。當(dāng)前無(wú)java實(shí)現(xiàn)。

支持的服務(wù)模型:

參數(shù) 描述
TSimpleServer 簡(jiǎn)單的單線程服務(wù)模型,常用于測(cè)試
TThreadPoolServer 多線程服務(wù)模型,使用標(biāo)準(zhǔn)的阻塞式IO。
TNonblockingServer 多線程服務(wù)模型,使用非阻塞式IO(需使用TFramedTransport數(shù)據(jù)傳輸方式)

Thrift 下載及安裝

如何獲取Thrift

  1. 官網(wǎng):http://thrift./
  2. golang的Thrift包:
go get git./thrift.git/lib/go/thrift

如何安裝Thrift

mac下安裝Thrift,參考上一篇介紹
其他平臺(tái)安裝自行挖掘,呵呵。
安裝后通過(guò)

liuxinmingMacBook-Rro#:thrift -version
Thrift version 0.9.2 #看到這一行表示安裝成功

Golang、PHP通過(guò)Thrift調(diào)用

先發(fā)個(gè)官方各種語(yǔ)言DEMO地址 https://git1-us-west./repos/asf?p=thrift.git;a=tree;f=tutorial;h=d69498f9f249afaefd9e6257b338515c0ea06390;hb=HEAD

Thrift的協(xié)議庫(kù)IDL文件

語(yǔ)法參考

參考資料

http://www.cnblogs.com/tianhuilove/archive/2011/09/05/2167669.html

http://my.oschina.net/helight/blog/195015

基本類型


  • bool: 布爾值 (true or false), one byte
  • byte: 有符號(hào)字節(jié)
  • i16: 16位有符號(hào)整型
  • i32: 32位有符號(hào)整型
  • i64: 64位有符號(hào)整型
  • double: 64位浮點(diǎn)型
  • string: Encoding agnostic text or binary string

基本類型中基本都是有符號(hào)數(shù),因?yàn)橛行┱Z(yǔ)言沒(méi)有無(wú)符號(hào)數(shù),所以Thrift不支持無(wú)符號(hào)整型。

特殊類型


  • binary: Blob (byte array) a sequence of unencoded bytes

這是string類型的一種變形,主要是為java使用

struct結(jié)構(gòu)體

thrift中struct是定義為一種對(duì)象,和面向?qū)ο笳Z(yǔ)言的class差不多.,但是struct有以下一些約束:
struct不能繼承,但是可以嵌套,不能嵌套自己。
1. 其成員都是有明確類型
2. 成員是被正整數(shù)編號(hào)過(guò)的,其中的編號(hào)使不能重復(fù)的,這個(gè)是為了在傳輸過(guò)程中編碼使用。
3. 成員分割符可以是逗號(hào)(,)或是分號(hào)(;),而且可以混用,但是為了清晰期間,建議在定義中只使用一種,比如C++學(xué)習(xí)者可以就使用分號(hào)(;)。
4. 字段會(huì)有optional和required之分和protobuf一樣,但是如果不指定則為無(wú)類型–可以不填充該值,但是在序列化傳輸?shù)臅r(shí)候也會(huì)序列化進(jìn)去,
optional是不填充則部序列化。
required是必須填充也必須序列化。
5. 每個(gè)字段可以設(shè)置默認(rèn)值
6. 同一文件可以定義多個(gè)struct,也可以定義在不同的文件,進(jìn)行include引入。

struct Work {
  1: i32 num1 = 0,
  2: i32 num2,
  3: Operation op,
  4: optional string comment,
}

容器(Containers)

Thrift3種可用容器類型:


  • list(t): 元素類型為t的有序表,容許元素重復(fù)。
  • set(t):元素類型為t的無(wú)序表,不容許元素重復(fù)。對(duì)應(yīng)c++中的set,java中的HashSet,python中的set,php中沒(méi)有set,則轉(zhuǎn)換為list類型。
  • map(t,t): 鍵類型為t,值類型為t的kv對(duì),鍵不容許重復(fù)。對(duì)用c++中的map, Java的HashMap, PHP 對(duì)應(yīng) array, Python/Ruby 的dictionary。

容器中元素類型可以是除了service外的任何合法Thrift類型(包括結(jié)構(gòu)體和異常)。為了最大的兼容性,map的key最好是thrift的基本類型,有些語(yǔ)言不支持復(fù)雜類型的key,JSON協(xié)議只支持那些基本類型的key。
容器都是同構(gòu)容器,不失異構(gòu)容器。

實(shí)現(xiàn)Thrift TDL文件

batu.thrift文件:

/**
 * BatuThrift TDL
 * @author liuxinming
 * @time 2015.5.13
 */

namespace go batu.demo
namespace php batu.demo

/**
 * 結(jié)構(gòu)體定義
 */
struct Article{
 1: i32 id, 
 2: string title,
 3: string content,
 4: string author,
}

const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}

service batuThrift {        
        list<string> CallBack(1:i64 callTime, 2:string name, 3:map<string, string> paramMap),
        void put(1: Article newArticle),
}

編譯IDL文件,生成相關(guān)代碼

thrift -r --gen go batu.thrift
thrift -r --gen php batu.thrift  
thrift -r --gen php:server batu.thrift #生成PHP服務(wù)端接口代碼有所不一樣

Golang Service 實(shí)現(xiàn)

  1. 先按照golang的Thrift包

    go get git./thrift.git/lib/go/thrift

  2. 將Thrift生成的開(kāi)發(fā)庫(kù)復(fù)制到GOPATH中

    cp -r /Users/liuxinming/wwwroot/testphp/gen-go/batu $GOPATH/src

  3. 開(kāi)發(fā)Go server端代碼(后面的代碼,目錄我們放在$GOPATH/src/thrift 中運(yùn)行和演示)
    test.go文件:

package main

import (
    "batu/demo" #注意導(dǎo)入Thrift生成的接口包
    "fmt"
    "git./thrift.git/lib/go/thrift"
    "os"
    "time"
)

const (
    NetworkAddr = "127.0.0.1:9090" #監(jiān)聽(tīng)地址&端口
)

type batuThrift struct {
}

func (this *batuThrift) CallBack(callTime int64, name string, paramMap map[string]string) (r []string, err error) {
    fmt.Println("-->from client Call:", time.Unix(callTime, 0).Format("2006-01-02 15:04:05"), name, paramMap)
    r = append(r, "key:"+paramMap["a"]+"    value:"+paramMap["b"])
    return
}

func (this *batuThrift) Put(s *demo.Article) (err error) {
    fmt.Printf("Article--->id: %d\tTitle:%s\tContent:%t\tAuthor:%d\n", s.Id, s.Title, s.Content, s.Author)
    return nil
}

func main() {
    transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory())
    protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
    //protocolFactory := thrift.NewTCompactProtocolFactory()

    serverTransport, err := thrift.NewTServerSocket(NetworkAddr)
    if err != nil {
        fmt.Println("Error!", err)
        os.Exit(1)
    }

    handler := &batuThrift{}
    processor := demo.NewBatuThriftProcessor(handler)

    server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
    fmt.Println("thrift server in", NetworkAddr)
    server.Serve()
}

4.運(yùn)行g(shù)o服務(wù)端(監(jiān)聽(tīng)9090端口)

liuxinmingdeMacBook-Pro:thrift liuxinming$ go run test.go
thrift server in 127.0.0.1:9090

至此Go的Thrift服務(wù)端OK.

Golang Client 實(shí)現(xiàn)

goClient.go文件:

package main

import (
    "batu/demo"
    "fmt"
    "git./thrift.git/lib/go/thrift"
    "net"
    "os"
    "strconv"
    "time"
)

const (
    HOST = "127.0.0.1"
    PORT = "9090"
)

func main() {
    startTime := currentTimeMillis()

    transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory())
    protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()

    transport, err := thrift.NewTSocket(net.JoinHostPort(HOST, PORT))
    if err != nil {
        fmt.Fprintln(os.Stderr, "error resolving address:", err)
        os.Exit(1)
    }

    useTransport := transportFactory.GetTransport(transport)
    client := demo.NewBatuThriftClientFactory(useTransport, protocolFactory)
    if err := transport.Open(); err != nil {
        fmt.Fprintln(os.Stderr, "Error opening socket to "+HOST+":"+PORT, " ", err)
        os.Exit(1)
    }
    defer transport.Close()

    for i := 0; i < 10; i++ {
        paramMap := make(map[string]string)
        paramMap["a"] = "batu.demo"
        paramMap["b"] = "test" + strconv.Itoa(i+1)
        r1, _ := client.CallBack(time.Now().Unix(), "go client", paramMap)
        fmt.Println("GOClient Call->", r1)
    }

    model := demo.Article{1, "Go第一篇文章", "我在這里", "liuxinming"}
    client.Put(&model)
    endTime := currentTimeMillis()
    fmt.Printf("本次調(diào)用用時(shí):%d-%d=%d毫秒\n", endTime, startTime, (endTime - startTime))

}

func currentTimeMillis() int64 {
    return time.Now().UnixNano() / 1000000
}

goClient運(yùn)行后結(jié)果:

liuxinmingdeMacBook-Pro:thrift liuxinming$ go run goClient.go
GOClient Call-> [key:batu.demo value:test1]
GOClient Call-> [key:batu.demo value:test2]
GOClient Call-> [key:batu.demo value:test3]
GOClient Call-> [key:batu.demo value:test4]
GOClient Call-> [key:batu.demo value:test5]
GOClient Call-> [key:batu.demo value:test6]
GOClient Call-> [key:batu.demo value:test7]
GOClient Call-> [key:batu.demo value:test8]
GOClient Call-> [key:batu.demo value:test9]
GOClient Call-> [key:batu.demo value:test10]
本次調(diào)用用時(shí):1431583140857-1431583140855=2毫秒

PHP Client 實(shí)現(xiàn)

  1. 首先去下載Thrift,git庫(kù)地址為:https://github.com/apache/thrift
  2. 新建項(xiàng)目目錄testphp,然后把thrift/lib/php/lib復(fù)制到testphp目錄下面
  3. 復(fù)制生成的gen-php到testphp目錄下面
  4. 客戶端代碼
<?php
/**
 * Thrift RPC - PHPClient
 * @author liuxinming
 * @time 2015.5.13
 */
namespace  batu\testDemo;
header("Content-type: text/html; charset=utf-8");
$startTime = getMillisecond();//記錄開(kāi)始時(shí)間

$ROOT_DIR = realpath(dirname(__FILE__).'/');
$GEN_DIR = realpath(dirname(__FILE__).'/').'/gen-php';
require_once $ROOT_DIR . '/Thrift/ClassLoader/ThriftClassLoader.php';

use Thrift\ClassLoader\ThriftClassLoader;
use Thrift\Protocol\TBinaryProtocol;
use Thrift\Transport\TSocket;
use Thrift\Transport\TSocketPool;
use Thrift\Transport\TFramedTransport;
use Thrift\Transport\TBufferedTransport;

$loader = new ThriftClassLoader();
$loader->registerNamespace('Thrift',$ROOT_DIR);
$loader->registerDefinition('batu\demo', $GEN_DIR);
$loader->register();

$thriftHost = '127.0.0.1'; //UserServer接口服務(wù)器IP
$thriftPort = 9090;            //UserServer端口

$socket = new TSocket($thriftHost,$thriftPort);  
$socket->setSendTimeout(10000);#Sets the send timeout.
$socket->setRecvTimeout(20000);#Sets the receive timeout.
//$transport = new TBufferedTransport($socket); #傳輸方式:這個(gè)要和服務(wù)器使用的一致 [go提供后端服務(wù),迭代10000次2.6 ~ 3s完成]
$transport = new TFramedTransport($socket); #傳輸方式:這個(gè)要和服務(wù)器使用的一致[go提供后端服務(wù),迭代10000次1.9 ~ 2.1s完成,比TBuffer快了點(diǎn)]
$protocol = new TBinaryProtocol($transport);  #傳輸格式:二進(jìn)制格式
$client = new \batu\demo\batuThriftClient($protocol);# 構(gòu)造客戶端

$transport->open();  
$socket->setDebug(TRUE);

for($i=1;$i<11;$i++){
    $item = array();
    $item["a"] = "batu.demo";
    $item["b"] = "test"+$i;
    $result = $client->CallBack(time(),"php client",$item); # 對(duì)服務(wù)器發(fā)起rpc調(diào)用
    echo "PHPClient Call->".implode('',$result)."<br>";
}

$s = new \batu\demo\Article();
$s->id = 1;
$s->title = '插入一篇測(cè)試文章';
$s->content = '我就是這篇文章內(nèi)容';
$s->author = 'liuxinming';
$client->put($s);

$s->id = 2;
$s->title = '插入二篇測(cè)試文章';
$s->content = '我就是這篇文章內(nèi)容';
$s->author = 'liuxinming';
$client->put($s);

$endTime = getMillisecond();

echo "本次調(diào)用用時(shí): :".$endTime."-".$startTime."=".($endTime-$startTime)."毫秒<br>";

function getMillisecond() {
    list($t1, $t2) = explode(' ', microtime());
    return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
}

$transport->close();

PHP運(yùn)行后結(jié)果:

PHPClient Call->key:batu.demo value:1
PHPClient Call->key:batu.demo value:2
PHPClient Call->key:batu.demo value:3
PHPClient Call->key:batu.demo value:4
PHPClient Call->key:batu.demo value:5
PHPClient Call->key:batu.demo value:6
PHPClient Call->key:batu.demo value:7
PHPClient Call->key:batu.demo value:8
PHPClient Call->key:batu.demo value:9
PHPClient Call->key:batu.demo value:10
本次調(diào)用用時(shí): :1431582183296-1431582183290=6毫秒

Go服務(wù)端看到打印數(shù)據(jù):

–>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:1]
–>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:2]
–>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:3]
–>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:4]
–>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:5]
–>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:6]
–>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:7]
–>from client Call: 2015-05-13 22:43:03 php client map[b:8 a:batu.demo]
–>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:9]
–>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:10]
Article—>id: 1 Title:插入一篇測(cè)試文章 Content:我就是這篇文章內(nèi)容 Author:liuxinming
Article—>id: 2 Title:插入二篇測(cè)試文章 Content:我就是這篇文章內(nèi)容 Author:liuxinming

完結(jié),至此一個(gè)Golang的Thrift服務(wù)端 和 PHP的Thrift客戶端完成!


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多