Hadoop壓縮的圖文教程

近期由於Hadoop集群機器硬盤資源緊張,有需求讓把 Hadoop 集群上的歷史數據進行下壓縮,開始從網上查找的都是關於各種壓縮機制的對比,很少有關於怎麼壓縮的教程(我沒找到。。),再此特記錄下本次壓縮的過程,方便以後查閱,利己利人。

 

本文涉及的所有 jar包、腳本、native lib 見文末的相關下載 ~

 

我的壓縮版本: 

Jdk 1.7及以上

Hadoop-2.2.0 版本

 

壓縮前環境準備:

關於壓縮算法對比,網上資料很多,這裏我用的是 Bzip2 的壓縮方式,比較中庸,由於是Hadoop自帶的壓縮機制,也不需要額外下載別的東西,只需要在 Hadoop根目錄下 lib/native 文件下有如下文件即可:

 

 

 

 

壓縮之前要檢查 Hadoop 集群支持的壓縮算法: hadoop checknative

每台機器都要檢查一下,都显示如圖 true 則說明 集群支持 bzip2 壓縮,

如果显示false 則需要將上圖的文件下載拷貝到 Hadoop根目錄下 lib/native

 

 

 

壓縮程序介紹:

 

壓縮程序用到的類 getFileList(獲取文件路徑) 、 FileHdfsCompress(壓縮類)、FileHdfsDeCompress(解壓縮類) ,只用到這三個類即可完成壓縮/解壓縮操作。

 

 

 

 

getFileList 作用:遞歸打印 傳入文件目錄下文件的根路徑,包括子目錄下的文件。開始想直接輸出到文件中,後來打包放到集群上運行時,發現文件沒有內容,可能是由於分佈式運行的關係,所以就把路徑打印出來,人工在放到文件中。

 

核心代碼:
public static void listAllFiles(String path, List<String> strings) throws IOException {
        FileSystem hdfs = getHdfs(path);
        Path[] filesAndDirs = getFilesAndDirs(path);

        for(Path p : filesAndDirs){
            if(hdfs.getFileStatus(p).isFile()){
                if(!p.getName().contains("SUCCESS")){
                    System.out.println(p);
                }
            }else{
                listAllFiles(p.toString(),strings);
            }
        }
       // FileUtils.writeLines(new File(FILE_LIST_OUTPUT_PATH), strings,true);

    }

public static FileSystem getHdfs(String path) throws IOException {
        Configuration conf = new Configuration();
        return FileSystem.get(URI.create(path),conf);
    }


public static Path[] getFilesAndDirs(String path) throws IOException { FileStatus[] fs = getHdfs(path).listStatus(new Path(path)); return FileUtil.stat2Paths(fs); }

  

 FileHdfsCompress:壓縮程序非常簡單,對應程序里的 FileHdfsCompress 類,(解壓縮是 FileHdfsDeCompress),採用的是Hadoop 原生API  ,將Hadoop集群上原文件讀入作為輸入流,將壓縮路徑的輸入流作為輸出,再使用相關的壓縮算法即,代碼如下:

 

核心代碼:

 //指定壓縮方式
            Class<?> codecClass = Class.forName(COMPRESS_CLASS_NAME);

            Configuration conf = new Configuration();
            CompressionCodec codec = (CompressionCodec)ReflectionUtils.newInstance(codecClass, conf);
            // FileSystem fs = FileSystem.get(conf);
            FileSystem fs = FileSystem.get(URI.create(inputPath),conf);

            //原文件路徑 txt 用原本的輸入流讀入
            FSDataInputStream in = fs.open(new Path(inputPath));

            //創建 HDFS 上的輸出流,壓縮路徑
            //通過文件系統獲取輸出流
            OutputStream out = fs.create(new Path(FILE_OUTPUT_PATH));
            //對輸出流的數據壓縮
            CompressionOutputStream compressOut = codec.createOutputStream(out);
            //讀入原文件 壓縮到HDFS上 輸入--普通流  輸出-壓縮流
            IOUtils.copyBytes(in, compressOut, 4096,true);

  

以下是代碼優化的過程,不涉及壓縮程序使用,不感興趣同學可以跳過 ~ :

 

在實際編碼中,我其實是走了彎路的,一開始並沒有想到用 Hadoop API 就能實現壓縮解壓縮功能,代碼到此其實是經歷了優化迭代的過程。

 

最開始時壓縮的思路就是 將文件讀進來,再壓縮出去,一開始使用了 MapReduce 的方式,在編碼過程中,由於對生成壓縮文件的路徑還有要求,又在 Hadoop 輸出時自定義了輸出類來使的輸出文件的名字符合要求,不是 part-r-0000.txt ,而是時間戳.txt 的格式,至此符合原線上路徑的要求。

 

而在實際運行過程中發現,MR 程序需要啟動 Yarn,並佔用Yarn 資源,由於壓縮時間較長,有可能會長時間佔用 集群資源不釋放,後來發現 MR 程序的初衷是用來做并行計算的,而壓縮僅僅是 map 任務讀取一條就寫一條,不涉及計算,就是內容的簡單搬運。所以這裏放棄了使用 MR 想着可不可以就用簡單的 Hadoop API 就完成壓縮功能,經過一番嘗試后,發現真的可行! 使用了 Hadoop API 釋放了集群資源,壓縮速度也還可以,這樣就把這個壓縮程序當做一個後台進程跑就行了也不用考慮集群資源分配的問題

 

實測壓縮步驟:

 

1 將項目打包,上傳到hadoop 集群任一節點即可,準備好相應的腳本,輸入數據文件,日誌文件,如下圖:

 

 

 

 

2 使用獲取文件路徑腳本,打印路徑: 

 

 

 

getFileLish.sh 腳本內容如下,就是簡單調用,傳入參數為 hadoop集群上 HDFS 上目錄路徑

#!/bin/sh

echo "begin get fileList"

echo "第一個參數$1"

if [ ! -n "$1" ]; then
echo "check param!"
fi

#original file
hadoop jar hadoop-compress-1.0.jar com.people.util.getFileList  $1

  

3 將 打印的路徑 粘貼到 compress.txt 中,第 2 步中會把目錄的文件路徑包括子目錄路徑都打印出來,將其粘貼進  compress.txt 中即可,注意 文件名可隨意定

 

4 使用壓縮腳本即可,sh compress.sh /data/new_compress/compress.txt  ,加粗的部分是腳本的參數意思是 第3步中文件的路徑,注意:這裏只能是絕對路徑,不然可能報找不到文件的異常。

 

 

 compress.sh 腳本內容如下,就是簡單調用,傳入參數為 第3步中文件的絕對路徑

 

#!/bin/sh
echo "begin compress"

echo "第一個參數$1"

if [ ! -n "$1" ]; then
echo "check param!"
fi


hadoop jar hadoop-compress-1.0.jar com.people.compress.FileHdfsCompress  $1 >> /data/new_compress/compress.log 2>&1 &

  

 

5 查看壓縮日誌,發現後台程序已經開始壓縮了!,tail  -f  compress.log

 

6 如果感覺壓縮速度不夠,可以多台機器執行腳本,也可以一台機器執行多個任務,因為這個腳本任務是一個後台進程,不會佔用集群 Yarn 資源。

 

 相關下載:

 

程序源碼下載: git@github.com:fanpengyi/hadoop-compress.git

 

Hadoop 壓縮相關需要的 腳本、jar包、lib 下載: 關注公眾號 “大數據江湖”,後台回復 “hadoop壓縮”,即可下載

 

長按即可關注

 

 — The End —

 

 

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

※專營大陸快遞台灣服務

台灣快遞大陸的貨運公司有哪些呢?

Graphviz 畫圖的一些總結

Graphviz 是一個自動排版的作圖軟件,可以生成 png pdf 等格式。

一切以官方文檔為準,博客只是參考。這裏做一個自己學習的記錄。

dot 語言

Graphviz 構建組件為 圖,節點,邊,用屬性對其進行描述。

以下是定義DOT語言的抽象語法,約束的規則如下:

  • 元素的終止以 粗體 显示
  • 文字字符用單引號 引起來
  • 圓括號 () 的內容為必選項
  • 方括號 [] 為可選項目
  • 豎杠 | 為擇一選擇
聲明 結構
graph [ strict ] (graph | digraph) [ ID ] ‘{‘ stmt_list ‘}’
stmt_list [ stmt [ ‘;‘ ] stmt_list ]
stmt node_stmt | edge_stmt | attr_stmt | ID ‘=‘ ID | subgraph
attr_stmt (graph | node | edge) attr_list
attr_list ‘[‘** [ a_list ] **’]’ [ attr_list ]
a_list ID ‘=’ ID [ (‘;’ | ‘,’) ] [ a_list ]
edge_stmt (node_id | subgraph) edgeRHS [ attr_list ]
edgeRHS edgeop (node_id | subgraph) [ edgeRHS ]
node_stmt node_id [ attr_list ]
node_id ID [ port ]
port :‘ ID [ ‘:‘ compass_pt ] | ‘:‘ compass_pt
subgraph [ subgraph [ ID ] ] ‘{‘ stmt_list ‘}
compass_pt (n | ne | e | se | s | sw | w | nw | c | _)

ID 其實就是一個字符串,為該組件的名稱或者屬性的名稱,命名規則如下:

  1. 所有的字母 [a-zA-Z\200-\377] 下劃線,数字 [0-9],数字不能出現在起始位置
  2. 純数字 $[-]^?(.[0-9]^+ | [0-9]^+(.[0-9]*)6? $
  3. 所有用雙引號引用的字符串 "..."
  4. HTML 格式的字符串 <>

dot 語法的關鍵字

  • strict, 嚴格的圖限定,禁止創建多個相同的邊
  • graph, 無向圖. 在圖的創建時必須聲明為有向圖還是無向圖
  • digraph, 有向圖
  • node, 節點
  • edge, 邊
  • subgraph, 子圖

通過 dot 的抽象語法可以看到

  1. 整個 graph 必須使用 graph 或 digraph {} 進行限定說明圖的屬性
  2. 圖裡面的聲明列表可以為空,也可以為多個,每個聲明后的 ; 為可選項
  3. 聲明有幾種類型
    1. 節點 node
    2. edge
    3. 子圖 subgraph
    4. 屬性列表
    5. ID = ID, 這個類型暫時還沒有看到有什麼作用
  4. 屬性列表
    1. 必須使用中括號 [ ] 將列表項括起來
    2. 列表項為可選
  5. 屬性列表項
    1. 以 key = value 的形式存在,列表項可選擇 ‘,‘ 和 ‘;‘ 結尾
    2. 可存在多個列表項
  6. 邊的聲明
    1. 首端為 節點標識符或者子圖,
    2. 右部分由邊連接節點標識符或者子圖構成,右部分可以存在多個
    3. 尾部可選屬性列表
  7. 節點的聲明
    示例 節點的用法 node0 [label = "<postid1> string|<postid2> string|<postid3> string3", height=.5]` node0:head[color=lightblue] // 設置該部分的顏色
    1. 首部為節點標識符 節點部分(post) 方向 組成,其中后兩項為可選項。
    2. 後半部分為可選的屬性列表
方向 說明
n north 北
ne north east
e east 東
se south east 東南
s south 南
sw south west 西南
w west 西
nw north west 西北
c center 中部
_ 任意

一個方向的示例

digraph action {
    node [shape = record,height=.1];

    node0 [label = "<head> head|<body> body|<foot> foot", height=.5]
    node2 [shape = box label="mind"]

    node0:head:n -> node2:n [label = "n"]
    node0:head:ne -> node2:ne [label = "ne"]
    node0:head:e -> node2:e [label = "e"]
    node0:head:se -> node2:se [label = "se"]
    node0:head:s -> node2:s [label = "s"]
    node0:head:sw -> node2:sw [label = "sw"]
    node0:head:w -> node2:w [label = "w"]
    node0:head:nw -> node2:nw [label = "nw"]
    node0:head:c -> node2:c [label = "c"]
    node0:head:_ -> node2:_ [label = "_"]

    node0:body[style=filled color=lightblue]
}

效果如下 圖-1

繪製屬性

一個圖中有非常多的 node 和 edge,如果每次都需要聲明一個節點的屬性會非常麻煩,有一個簡單的方式為聲明一個公共的屬性如

digraph action {
    rankdir = LR // 設置方向
    node [shape=box color=blue]
    edge [color=red]

    node1 // 默認節點屬性
    node2 [color=lightblue] // 屬於該節點的顏色屬性
    node1 -> node2 // 默認邊屬性 
    node2 -> node1 [color=green] // 屬於該變的屬性
}

在聲明位置之後的節點都有一個 默認 的形狀和顏色屬性。

全部的屬性見,這裏列舉部分常用的屬性

  • charset 編碼,一般設置 UTF-8
  • fontname 字體名稱,這個在中文的情況需要設置,否則導出圖片的時候會亂碼,一般設置微軟雅黑(“Microsoft YaHei”), linux 下也是同樣設置系統帶的字體就好,其他字體設置見 屬性
  • fontcolor 字體顏色
  • fontsize 字體大小,用於文本內容
  • fillcolor 用於填充節點或者集群(cluster)的背景顏色。
  • size 圖形的最大寬度和高度
  • label 圖形上的文本標記
  • margin 設置圖形的邊距
  • pad 指定將繪製區域擴展到繪製圖形所需的最小區域的長度(以英寸為單位)
  • style 設置圖形組件的樣式信息。 對於聚類子圖或者節點,如果style = “filled”,則填充聚類框的背景
  • rankdir 設置圖形布局的排列方向 (全局只有一個生效). “TB”, “LR”, “BT”, “RL”, 分別對應於從上到下,從左到右,從下到上和從右到左繪製的有向圖。
  • ranksep 以英寸為單位提供所需的排列間隔
  • ratio 設置生成圖片的縱橫比

節點(node)

節點的默認屬性為 shape = ellipse, width = .75, height = 0.5 並且用節點標識符作為節點的显示文字。

如圖一中所示,聲明兩個節點 node0 和 node2,node0 或 node2 就表示這個節點的節點標識符,後面緊跟的是該節點的屬性列表;另一種用法為 節點標識符:節點部分:方向[屬性列表] node0:body[style=filled color=lightblue], 這個為單一節點聲明的方式。

節點中最基本的屬性為:

  • shape 形狀,全部形狀見,一些常用的圖形有
  • width height, 圖形的寬度和高度,如果設置了 fixedsize 為 true,則寬和高為最終的長度
  • fixedsize, 如果為false,節點的大小由其文本內容所需要的最小值決定
  • rank 子圖中節點上的排列等級約束. 最小等級是最頂部或最左側,最大等級是最底部或最右側。
    • same. 所有節點都位於同一等級
    • min. 所有節點都位於最小等級上
    • source. 所有節點都位於最小等級上,並且最小等級上的唯一節點屬於某個等級 source 或 min 的子圖.
    • max sink. 和上類似

邊 (edge)

有向圖中的的邊用 -> 表示,無向圖用 -- 表示。

可以同時連接多個節點或者子圖,但是只能有一個屬性列表,如下

digraph {
    rankdir = LR
    A -> B -> c[color=green]
}

一些關於邊的屬性如下:

digraph {
    rankdir = LR
    splines = ortho

    A -> B -> C -> D -> F [color = green]
    E -> F -> B -> D [color = blue]
    B -> E -> H[color = red]
}
  • len 首選邊的長度
  • weight 邊的權重, 權重越大越接近邊的長度
  • lhead 邏輯邊緣的頭部(箭頭那個位置),compound 設置為 true 時,邊被裁減到子圖的邊界處
  • ltail 類似 lhead
  • headlabel 邊上靠近箭頭部分的標籤
  • taillabel 邊上靠近尾部部分的標籤
    設置 A->B->C->D->F的權重最大,修改綠色的分支的權重為 100,使其變成主要邏輯分支。

  • splines 控制如何以及是否表示邊緣。其值如下
    • none 或者 “”, 無邊
    • true 或者 spline, 樣條線(無規則,可為直或者曲線)
    • false 或者 line, 直線段
    • polyline, 折線
    • curved, 曲弧線,兩條?
    • ortho, 正直的線(橫豎)
  • dir 設置繪製箭頭的邊緣類型

子圖

subgraph 必須配合 cluster 一起使用,用法為 subgraph cluster* {}

需要設置 compound 為 true,則在群集之間留出邊緣,子圖的邊界關係在 邊 的定義中有給出,這裏直接給個示例。

digraph G {
    compound = true  // 允許子圖間存在邊
    ranksep = 1
    node [shape = record]

    subgraph cluster_hardware {
        label = "hardware"
        color = lightblue
        CPU Memory
    }

    subgraph cluster_kernel {
        label = "kernel"
        color = green
        Init IPC
    }

    subgraph cluster_libc {
        label = "libc"
        color = yellow
        glibc
    }

    CPU -> Init [lhead = cluster_kernel ltail = cluster_hardware]
    IPC -> glibc [lhead = cluster_libc ltail = cluster_kernel]
}

示例

TCP IP 狀態流程圖

展示了兩個版本,怎麼把這些圖形節點稍微規範的显示出來

digraph {
    compound=true
    fontsize=10
    margin="0,0"
    ranksep = .75
    nodesep = .65

    node [shape=Mrecord fontname="Inconsolata, Consolas", fontsize=12, penwidth=0.5]
    edge [fontname="Inconsolata, Consolas", fontsize=10, arrowhead=normal]


    "TCP/IP State Transition" [shape = "plaintext", fontsize = 16]

    // now start server state transition
    "CLOSED" -> "LISTEN" [style = blod, label = "應用:被動打開\n發送:<無>"];
    "LISTEN" -> "SENT_REVD" [style = blod, label = "接收:SYN\n發送:SYN,ACK"]
    "SENT_REVD" -> "ESTABLISHED" [style = blod, label = "接收:ACK\n發送:<無>", weight = 20]
    "ESTABLISHED" -> "CLOSE_WAIT" [style = blod, label = "接收:FIN\n發送:ACK", weight = 20]

    subgraph cluster_passive_close {    
        style = dotted
        margin = 10

        passive_close [shape = plaintext, label = "被動關閉", fontsize = 14]

        "CLOSE_WAIT" -> "LAST_ACK" [style = blod, label = "應用:關閉\n發送:FIN", weight = 10]
    }
    "LAST_ACK" -> "CLOSED" [style = blod, label = "接收:ACK\n發送:<無>"]

    // now start client state transition
    "CLOSED" -> "SYN_SENT" [style = dashed, label = "應用:主動打開\n發送:SYN"]; 
    "SYN_SENT" -> "ESTABLISHED" [style = dashed, label = "接收:SYN,ACK\n發送:ACK", weight = 25]
    "SYN_SENT" -> "SENT_REVD" [style = dotted, label = "接收:SYN\n發送:SYN,ACK\n同時打開"]
    "ESTABLISHED" -> "FIN_WAIT_1" [style = dashed, label = "應用:關閉\n發送:FIN", weight = 20]
    
    subgraph cluster_active_close {
        style = dotted
        margin = 10
        
        active_open [shape = plaintext, label = "主動關閉", fontsize = 14]

        "FIN_WAIT_1" -> "FIN_WAIT_2" [style = dashed, label = "接收:ACK\n發送:<無>"]
        "FIN_WAIT_2" -> "TIME_WAIT" [style = dashed, label = "接收:FIN\n發送:ACK"]
        "FIN_WAIT_1" -> "CLOSING" [style = dotted, label = "接收:ACK\n發送:<無>"]
        "FIN_WAIT_1" -> "TIME_WAIT" [style = dotted, label = "接收:SYN,ACK\n發送:ACK"]
        "CLOSING" -> "TIME_WAIT" [style = dotted]
    }
    
    "TIME_WAIT" -> "CLOSED" [style = dashed, label = "2MSL超時"]
}

這是一個很挫的版本,排版亂飛了。

digraph rankdot {
    compound=true
    margin="0,0"
    ranksep = .75
    nodesep = 1
    pad = .5
    //splines = ortho

    node [shape=Mrecord, charset = "UTF-8" fontname="Microsoft YaHei", fontsize=14]
    edge [charset = "UTF-8" fontname="Microsoft YaHei", fontsize=11, arrowhead = normal]


    CLOSED -> LISTEN [style = dashed, label = "應用:被動打開\n發送:<無>", weight = 100];
    
    "TCP/IP State Transition" [shape = "plaintext", fontsize = 16]

    {
        rank = same
        SYN_RCVD SYN_SENT
        point_1 [shape = point, width = 0]
        
        SYN_SENT -> point_1 [style = dotted, label = "應用關閉或者超時"]
        // SYN_SENT -> SYN_RCVD 這個一行代碼和上一行衝突了,syn_sent 會在syn_rcvd右邊
        SYN_RCVD -> SYN_SENT [style = dotted, dir = back, headlabel = "接收:SYN\n發送:SYN,ACK\n同時打開"]
    }

    LISTEN -> SYN_RCVD [style = dashed, headlabel = "接收:SYN\n發送:SYN,ACK"]
    SYN_RCVD -> LISTEN [style = dotted, headlabel = "接收:RST"]
    CLOSED:es -> SYN_SENT [style = blod, label = "應用:主動打開\n發送:SYN"]

    {
        rank = same
        ESTABLISHED CLOSE_WAIT

        ESTABLISHED -> CLOSE_WAIT [style = dashed, label = "接收:SYN,ACK\n發送:ACK"]
    }

    SYN_RCVD -> ESTABLISHED [style = dashed, label = "接收:ACK\n發送:<無>", weight = 9]
    SYN_SENT -> ESTABLISHED  [style = blod, label = "接收:SYN,ACK\n發送:ACK", weight = 10]

    {
        rank = same

        FIN_WAIT_1
        CLOSING 
        LAST_ACK
        point_2 [shape = point, width = 0]

        FIN_WAIT_1 -> CLOSING [style = dotted, label = "接收:FIN\n發送:ACK"]
        LAST_ACK -> point_2 [style = dashed, label = "接收:ACK\n發送:<無>"]
    }

    CLOSE_WAIT -> LAST_ACK [style = dashed, label = "應用:關閉\n發送:FIN", weight = 10]

    {
        rank = same
        FIN_WAIT_2  TIME_WAIT

        point_3 [shape = point, width = 0]
        TIME_WAIT -> point_3 [style = blod, label = "2MSL超時"]
    }

    ESTABLISHED -> FIN_WAIT_1 [style = blod, label = "應用:關閉\n發送:FIN"]
    FIN_WAIT_1 -> FIN_WAIT_2 [style = blod, headlabel = "接收:ACK\n發送:<無>", weight = 15]
    FIN_WAIT_2 -> TIME_WAIT [style = blod, label = "接收:FIN\n發送:ACK", weight = 10]

    CLOSING -> TIME_WAIT [style = dotted, label = "接收:ACK\n發送:<無>", weight = 15]
    FIN_WAIT_1 -> TIME_WAIT [style = dotted, label = "接收:ACK\n發送:<無>"]

    point_3 -> point_2 [arrowhead = none, style = dotted, weight = 10]
    point_2 -> point_1 [arrowhead = none, style = dotted]
    point_1 -> CLOSED [style = dotted]
}

這個版本看起來有內味了,最最最的主要的原因就是我使用 rank = same 屬性,將一些圖形固定在 同一列,一些需要橫豎的直線的地方使用 weight 來調整權重,達到橫豎的直接的效果,很多地方都是微調的結果。有一個很差的地方是 使用了rank限制若干圖形后,就不能使用 subgraph 屬性了,這樣就不能在若干不同部分的節點周邊畫線(對比關閉的區域)了。

epoll 相關數據結構及關係

digraph rankdot {
    compound=true
    margin="0,0"
    ranksep = .75
    nodesep = 1
    pad = .5
    rankdir = LR

    node [shape=record, charset = "UTF-8" fontname="Microsoft YaHei", fontsize=14]
    edge [style = dashed, charset = "UTF-8" fontname="Microsoft YaHei", fontsize=11]

    epoll [shape = plaintext, label = "epoll 相關結構及部分關係"]

    eventpoll [
        color = cornflowerblue,
        label = "<eventpoll> struct \n eventpoll |
            <lock> spinlock_t lock; |
            <mutex> struct mutex mtx; |
            <wq> wait_queue_head_t wq; |
            <poll_wait> wait_queue_head_t poll_wait; |
            <rdllist> struct list_head rdllist; |
            <ovflist> struct epitem *ovflist; |
            <rbr> struct rb_root_cached rbr; |
            <ws> struct wakeup_source *ws; |
            <user> struct user_struct *user; |
            <file> struct file *file; |
            <visited> int visited; |
            <visited_list_link> struct list_head visited_list_link;"
    ]

    epitem [
        color = sienna,
        label = "<epitem> struct \n epitem  |
            <rb>struct rb_node rbn;\nstruct rcu_head rcu; |
            <rdllink> struct list_head rdllink; |
            <next> struct epitem *next; |
            <ffd> struct epoll_filefd ffd; |
            <nwait> int nwait; |
            <pwqlist> struct list_head pwqlist; |
            <ep> struct eventpoll *ep; |
            <fllink> struct list_head fllink; |
            <ws> struct wakeup_source __rcu *ws; |
            <event> struct epoll_event event;"
    ]

    epitem2 [
        color = sienna,
        label = "<epitem> struct \n epitem |
            <rb>struct rb_node rbn;\nstruct rcu_head rcu; |
            <rdllink> struct list_head rdllink; |
            <next> struct epitem *next; |
            <ep> struct eventpoll *ep; |
             ··· |
             ··· "
    ]

    eppoll_entry [
        color = darkviolet,
        label = "<entry> struct \n eppoll_entry |
            <llink> struct list_head llink; |
            <base> struct epitem *base; |
            <wait> wait_queue_entry_t wait; |
            <whead> wait_queue_head_t *whead;"
    ]

    epitem:ep -> eventpoll:se [color = sienna]
    epitem2:ep -> eventpoll:se [color = sienna]
    eventpoll:ovflist -> epitem:next -> epitem2:next [color = cornflowerblue]
    eventpoll:rdllist -> epitem:rdllink -> epitem2:rdllink [dir = both]
    eppoll_entry:llink -> epitem:pwqlist [color = darkviolet]
    eppoll_entry:base -> epitem:nw  [color = darkviolet]
}

遺留問題

  1. 在以上TCP/IP 狀態變遷圖中,嘗試增加主動關閉方的區域邊框
  2. 嘗試增加 TCP/IP 的時序圖

使用 VSCode 進行預覽生成

  1. 在官網下載graphviz安裝包
  2. 安裝 vscode 插件 Graphviz Preview
  3. 在 settings.json 中添加 "graphvizPreview.dotPath": "graphviz_path\graphviz-2.38\\release\\bin\\dot.exe", graphviz_path 為所在路徑,這些修改一下既可
  4. 新建一個 dot 文件,右上角就會有預覽生成的按鈕了

參考

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

Thrift總結(四)Thrift實現雙向通信

前面介紹過 Thrift 安裝和使用,介紹了Thrift服務的發布和客戶端調用,可以查看我之前的文章:

但是,之前介紹的都是單向的客戶端發送消息,服務端接收消息。而客戶端卻得不到服務器的響應。

那如果我們要實現雙向通信(即:客戶端發送請求,服務端處理返回,服務端發送消息,客戶端處理返回)的功能,該怎麼實現呢?

 

其實在不涉及語言平台的制約,WebService或是webapi 就可以實現這種客戶端發起請求,服務端的處理的單向流程。

然而,實際場景中,可能我們的某些業務需求,更需要服務端能夠響應請求並處理數據。下面我通過一個demo案例,介紹下Thrift 是如何實現雙向通信的。

 

一、安裝Thrift

這裏不再贅述,戳這裏查看我上篇文章的介紹:

 

二、編寫Thrift IDL文件 

編寫thrift腳本,命名為student.thrift  如下:

service HelloWorldService{
    void SayHello(1:string msg);
}

生成service 的方法,之前的文章有介紹,這裏就不介紹了。

 

三、編寫服務端代碼

創建HelloThrift.Server 服務端工程,添加HelloWorldBidirectionServer類,HelloWorldBidirectionServer 實現了Iface接口用於接收客戶端消息,並有一個客戶端傳輸層對象集合用於記錄所有已連接的客戶端。

 public class HelloWorldBidirectionServer : HelloWorldBidirectionService.Iface
    {
        public void Run(int port)
        {
            try
            {
                TServerTransport transport = new TServerSocket(port);

                TTransportFactory transportFac = new TTransportFactory();

                TProtocolFactory inputProtocolFactory = new TBinaryProtocol.Factory();
                TThreadPoolServer server = new TThreadPoolServer(getProcessorFactory(), transport, transportFac, inputProtocolFactory);

                server.Serve();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public static List<TTransport> TransportCollection = new List<TTransport>();

        public void SayHello(string msg)
        {
            Console.WriteLine(string.Format("{0:yyyy/MM/dd hh:mm:ss} 服務端接收到消息: {1}", DateTime.Now, msg));
        }

        public void SayToClient(string msg)
        {
            try
            {
                foreach (TTransport trans in TransportCollection)
                {
                    TBinaryProtocol protocol = new TBinaryProtocol(trans);
                    HelloWorldBidirectionService.Client client = new HelloWorldBidirectionService.Client(protocol);
                    //Thread.Sleep(1000);
                    client.SayHello(msg);
                    //Console.WriteLine("發給了客戶端喲");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public TProcessorFactory getProcessorFactory()
        {
            return new HelloWorldBidirectionProcessor();
        }
    }

    public class HelloWorldBidirectionProcessor : TProcessorFactory
    {
        public TProcessor GetProcessor(TTransport trans, TServer server = null)
        {
            if (trans.IsOpen)
            {
                HelloWorldBidirectionServer.TransportCollection.Add(trans);
                Console.WriteLine("客戶端連上。");
            }

            HelloWorldBidirectionServer srv = new HelloWorldBidirectionServer();
            return new global::HelloWorldBidirectionService.Processor(srv);
        }
    }

 

四、編寫客戶端代碼

首先創建HelloThrift.Client客戶端項目,添加接收服務端消息的類HelloWorldBidirectionClient,裏面只有一個實現Iface接口的方法:

  public class HelloWorldBidirectionClient
    {
        static HelloWorldBidirectionService.Client client = null;
        public void ConnectAndListern(int port, string ip = "127.0.0.1")
        {
            //Tsocket: TCP/IP Socket接口
            TSocket tSocket = new TSocket(ip, port);
            //消息結構協議
            TProtocol protocol = new TBinaryProtocol(tSocket);
            try
            {
                if (client == null)
                {
                    client = new global::HelloWorldBidirectionService.Client(protocol);
                    tSocket.Open();//建立連接
                    StartListern(tSocket);//啟動監聽線程
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public void Say(string msg)
        {
            if (client != null)
                client.SayHello(msg);
        }

        void StartListern(TSocket tSocket)
        {
            Thread t = new Thread(new ParameterizedThreadStart(Run));
            t.Start(tSocket);
        }

        public void Run(object tSocket)
        {
            HelloWorldBidirectionService.Processor process = new HelloWorldBidirectionService.Processor(new HelloWorldBidirectionFace());

            try
            {
                while (process.Process(new TBinaryProtocol((TSocket)tSocket), new TBinaryProtocol((TSocket)tSocket)))
                {
                    Console.WriteLine("消息接收完成,等下一波,阻塞中......");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("連接斷開..." + ex.Message);
            }
        }

    }
    class HelloWorldBidirectionFace : HelloWorldBidirectionService.Iface
    {
        public void SayHello(string msg)
        {
            Console.WriteLine(string.Format("{0:yyyy/MM/dd hh:mm:ss} 收到服務端響應消息 {1}", DateTime.Now, msg));

        }
    }

 實現客戶端,ConnectAndListern方法可以與服務端建立連接,並開啟客戶端端口監聽來自服務端的信息。Say方法可將消息發送至服務端。

 

五、測試

 測試效果如下:

 

 

 

六、最後

  1. 關於使用Thrift 構建我們自己的rpc 的方法,這裏基本講完了。其他的方法本文就不再演示了,調用起來都是一樣。  

  2. 後續會簡單討論一下Thrift 框架的通信原理。

  3. 源代碼下載,

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

小三通海運與一般國際貿易有何不同?

小三通快遞通關作業有哪些?

美國蒙大拿州密蘇拉(Missoula)聯邦地區法官克里斯坦森(Dana Christensen)與環保人士及美國原住民站在同一陣線

美國蒙大拿州密蘇拉(Missoula)聯邦地區法官克里斯坦森(Dana Christensen)與環保人士及美國原住民站在同一陣線,駁回美國魚類暨野生動物管理局(US Fish and Wildlife Service)將灰熊從瀕危物種名單除名的決定。

環保人士主張,根據瀕臨滅絕物種保護法,對這些灰熊與蒙大拿州和下48州(Lower 48)的其他灰熊族群採取差別待遇,是生物學上靠不住且非法行為,法官也同意這類說法。

環保人士說,儘管灰熊數量有所回升,倘若沒有受到聯邦持續保護,牠們的復育情況就會受到影響。此外,氣候變遷導致灰熊食物供給出現變化和人為死亡率高,也對灰熊生存構成威脅。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※試算大陸海運運費!

每年聯合國大會召開之際,多國元首和政府領袖同時舉行的「氣候週」今天(25日)開跑

每年聯合國大會召開之際,多國元首和政府領袖同時舉行的「氣候週」今天(25日)開跑,他們敦促世界領袖緊急採取行動降低全球暖化。

波蘭12月將主辦聯合國氣候變化綱要公約第24次締約方會議(COP24),聯合國氣候首長艾斯皮諾薩(Patricia Espinosa)呼籲各國團結,支持2015年巴黎協定所訂規定,將全球暖化升溫限制在攝氏兩度以下。

艾斯皮諾薩表示,各國並未實現他們的承諾。並說:「各國目前依據巴黎協定做出的承諾,將使得全球溫度在2100年升高約三度。」

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

※專營大陸快遞台灣服務

台灣快遞大陸的貨運公司有哪些呢?

北極白鯨驚奇現身泰晤士河 再不回家專家憂安危

摘錄自2018年9月26日中央社報導

據英國各大媒體報導,一隻迷途的白鯨現身英國泰晤士河,第一次被目擊是25日在肯特郡(Kent)格雷夫森德(Gravesend)的泰晤士河段,當時白鯨正在駁船附近覓食,被暱稱為「班尼」(Benny),距離其原棲息地北極圈水域達數千公里。26日白鯨再次現身同個地點,引發是否迷航及可能遇險的擔憂。

鯨豚保育協會(WDC)海洋哺乳類動物科學家羅特(Rob Lott)表示,這隻白鯨正受到監控,以防牠擱淺。「但白鯨停留在泰晤士河口的時間愈長,就愈令人擔心。」

海洋生物保育慈善團體ORCA的保育學家巴比(Lucy Babey)表示:「這是白鯨出現在英國的最南端紀錄。」

英國海洋生物救援組織表示,英國最後一次發現白鯨蹤跡是3年前在北英格蘭的諾森伯蘭(Northumberland)海岸,以及北愛爾蘭,但極為罕見。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

蘇門答臘瀕危老虎 受困捕獸陷阱後死亡

摘錄自2018年9月26日中央社報導

印尼官員今天(26日)說,一頭被列為極度瀕危物種的蘇門答臘虎死屍在蘇門答臘島廖內省(Riau)的慕亞拉藍布村(Muara Lembu)附近山溝被發現,根據虎屍肚子上圍繞著陷阱裡的繩索研判,應是受困獵人所設陷阱後死亡。

稍早,當地村民告訴保育機構說,有人看到一頭雌蘇門答臘虎受困獵人為捕獵野豬設置的陷阱。但官員趕往現場後,已不見老虎。官員隔天回到原區域搜尋,才在附近山溝尋獲。

國際自然保育聯盟(IUCN)將蘇門答臘虎列為「極危」的瀕危動物。自然界只剩不到400頭蘇門答臘虎,環保人士說,由於蘇門答臘虎自然棲息地迅速縮減,使牠們與人類發生衝突的機率升高。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

小三通海運與一般國際貿易有何不同?

小三通快遞通關作業有哪些?

保護環境 越南明年起加徵汽油環保稅

摘錄自2018年9月21日中央社報導

為了保護和改善環境,越南政府自明年起將調漲對汽油等燃料產品的環境保護稅,其中汽油每公升環保稅將從現行收費3000越盾(約新台幣4元)提升為4000越盾。

越南國會常務委員會昨天(20日)通過有關環境保護稅的決議,自明年起將對相關產品加徵環保稅,希望藉此保護與改善環境,減少污染物排放。

根據這項決議,汽油每公升環保稅將從現行收費3000越盾提升為4000越盾,柴油從1500越盾升到2000越盾,燃油和潤滑油從900越盾升到2000越盾等;此外,煤炭、塑膠袋與除草劑等也被列入加徵環保稅的產品名單。

越南國會官員指出,加徵對汽油等燃料產品的環保稅後,國家預算每年將增加15.7兆越盾,這是一筆很大的稅收,有利用於保護與改善環境。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

小三通物流營運型態?

※快速運回,大陸空運推薦?

米其林啟動循環經濟 2048年輪胎永續用料達80%、百分百回收

環境資訊中心外電;姜唯 翻譯;林大利 審校;稿源:ENS

法國輪胎製造商米其林提出「Ambition 2048」計畫,要在2048年達到輪胎用料80%為永續材料,並且回收再利用率達到100%。



米其林新概念輪胎「VISION」。圖片來源:米其林Michelin

2018年全球報廢輪胎達10億個

世界永續發展工商理事會估計,2018年全世界將產生10億個報廢輪胎,約2500萬噸。今日全球輪胎再製率為70%,回收率為50%,多的20%轉化為能量。相較之下,塑膠包裝或容器每年回收率僅14%。

為實現「Ambition 2048」,米其林正在投資高科技回收技術,以期將永續材料比例拉高到80%。

米其林總部位於克萊蒙費朗,目前在全球有11萬1700名員工,遍佈170個國家,在17個國家擁有68個生產基地,2016年共生產1.87億個輪胎。

「Biobutterfly」計畫 啟動輪胎循環經濟

米其林計畫用它的新輪胎「VISION」建立循環經濟。這種新概念輪胎不需要充氣,將採用生物來源和回收材料製成,胎面可由生物分解,透過3D列印再製。



米其林新輪胎「VISION」。圖片來源:米其林Michelin

今日輪胎的成份包含超過200種原料。輪胎工業中使用的橡膠中有60%是用石油衍生碳氫化合物製成,剩下的40%仍然是天然橡膠。

米其林的「Ambition 2048」永續發展目標包括致力研究生物來源材料。2012年米其林與「Axens」石化公司和法國石油能源研究所(IFP Energies Nouvelles)共同啟動「Biobutterfly」計畫。

「Biobutterfly」計畫致力於透過生物材料製作合成橡膠,例如木材、禾稈(straw)和甜菜。

專利技術 回收輪胎轉化為永續材料

米其林也試著將更多可回收和可再生材料整合進輪胎中。2017年底米其林收購了總部位於美國喬治亞州的「Lehigh Technologies」化學公司,該公司的專利技術是把回收輪胎轉製成高科技微粉化橡膠粉末。



微粉化橡膠粉末。圖片來源:Lehigh Technologies

這些創新材料減少了輪胎生產所需的非再生原料數量,如合成橡膠或碳煙。

微粉化橡膠粉末是一種低成本的永續材料,可代替輪胎製程中使用的其他材料,以及塑膠、瀝青和建築材料。

世界許多輪胎大廠以及瀝青和建築材料專業公司已經是「Lehigh Technologies」公司的客戶。

藉著「Ambition 2048」,米其林估計將實現:

*每年省下3300萬桶石油,足以填滿16.5個超級油輪
*法國每個人一個月的總能量消耗
*每年省下一台一般轎車(8L / 100公里)跑650億公里的油耗

Sustainable Ambitions: Michelin Plans for 2048 CLERMONT-FERRAND, France, September 24, 2018 (ENS)

To the French tire manufacturer Michelin, Ambition 2048 means a whole new strategy of using sustainable materials in tire manufacturing and recycling. It means that in the year 2048 Michelin plans to manufacture its tires using 80 percent sustainable materials, and that 100 percent of those tires will be recycled.



圖片來源:米其林Michelin

Headquartered in Clermont-Ferrand, Michelin is present in 170 of the world’s 197 countries, has 111,700 employees and operates 68 production facilities in 17 countries, which collectively produced 187 million tires in 2016.

The World Business Council for Sustainable Development estimates that in 2018 there will be one billion end-of-life tires generated in the world – around 25 million tons.

Today the worldwide recovery rate for tires is 70 percent and the recycling rate is 50 percent. The remaining 20 percent are transformed into energy. By comparison, 14 percent of plastic packaging or containers are recovered each year.

To accomplish Ambition 2048, Michelin is investing in high technology recycling technologies that will enable the company to increase this content to 80 percent sustainable material.

Michelin plans to help create a circular economy with a new tire concept called VISION. This airless tire would be made of bio-sourced and recycled products with a biodegradable tread that is renewable with a 3D printer. 

Today, over 200 raw materials go into tire composition. Sixty percent of the rubber used in the tire industry is synthetic, produced from petroleum-derived hydrocarbons, although natural rubber is still necessary for the remaining 40 percent.

Michelin’s Ambition 2048 sustainable development goal includes a commitment to research into bio-sourced materials, such as Biobutterfly, a program launched in 2012 with Axens and IFP Energies Nouvelles.

Biobutterfly involves the creation of synthetic elastomers from biomass such as wood, straw or beet.

Michelin is integrating more recycled and renewable materials in its tires. This strategy motivated the acquisition in late 2017 of the American company Lehigh Technologies, based in Georgia, which specializes in high technology micronized rubber powders derived from recycled tires.

These innovative materials reduce the amount of non-renewable raw materials needed for tire production, such as elastomers or carbon black.

Micronized rubber powder is a low cost sustainable material that can substitute for other components used in the manufacture of tires, as well as plastics, asphalt and construction materials.

Major world tire manufacturers, as well as companies specialized in asphalt and construction materials are already Lehigh Technologies’ customers.

When Ambition 2048 is achieved, Michelin estimates that the potential savings will be equivalent to:

* – 33 million barrels of oil saved per year, enough to fill 16.5 supertankers
* – One month’s total energy consumption of everyone in France
* – 65 billion kilometers driven by an average sedan (8L / 100 km) per year

※ 全文及圖片詳見:

作者

如果有一件事是重要的,如果能為孩子實現一個願望,那就是人類與大自然和諧共存。

於特有生物研究保育中心服務,小鳥和棲地是主要的研究對象。是龜毛的讀者,認為龜毛是探索世界的美德。

延伸閱讀

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

台灣寄大陸海運貨物規則及重量限制?

大陸寄台灣海運費用試算一覽表

台中搬家,彰化搬家,南投搬家前需注意的眉眉角角,別等搬了再說!

噴藥害死蜜蜂 奧地利果農遭判刑

摘錄自2018年9月26日中央社報導

奧地利一名果農因違法噴灑殺蟲劑,隸屬鄰近2個養蜂人超過50個蜂群因此死亡。26日奧地利克拉根福法院(Klagenfurt)以「蓄意危害環境」,判處果農1年有期徒刑,至少需服刑4個月才可假釋,以及賠償超過2萬歐元(2萬3500美元)。

這名47歲果農針對他位於奧地利卡林西亞省(Carinthia)拉萬特地區(Lavanttal)的果樹噴灑藥效強大的殺蟲劑陶斯松(chlorpyrifos),當時果樹的花仍會吸引蜜蜂前去。法院指出,以他的經驗和訓練他人的角色,足以證明他知道自身行為會帶來何種後果。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

大陸寄台灣空運注意事項

大陸海運台灣交貨時間多久?

※避免吃悶虧無故遭抬價!台中搬家公司免費估價,有契約讓您安心有保障!