1. 程式人生 > >twemproxy0.4原理分析-系統初始化過程原理分析

twemproxy0.4原理分析-系統初始化過程原理分析

概述

本文介紹twemproxy的系統初始化過程。該過程包括以下幾個方面的內容:

  • 讀取配置檔案,根據配置檔案初始化資料結構
  • 和後臺伺服器建立連線,形成伺服器連線池
  • 初始化事件處理框架,並設定最開始的事件處理函式
  • 建立twemproxy的監聽socket,並把該監聽socket新增到事件處理框架中,用來監聽客戶端的連線請求。

載入配置檔案

twemproxy0.4是根據YAML檔案格式來進行後臺引數配置。在程序啟動時通過-c或–conf-file選項來指定配置檔案。啟動的實際命令如下例子:

cd twemproxy-0.4.1
./src/nutcracker -c ./conf/nutcracker.yml

若下載的是twemproxy0.4的原始碼,配置檔案的樣例檔案在原始碼根目錄下的conf目錄下。

樣例配置檔案example.yml如下:

alpha:
  listen: 0.0.0.0:22121
  hash: fnv1a_64
  distribution: ketama
  auto_eject_hosts: true
  redis: true
  server_retry_timeout: 2000
  server_failure_limit: 1
  servers:
   - 127.0.0.1:6379:1
   - 127.0.0.1:6378:1
   - 127.0.0.1:6377:1

beta:
  listen: 0.0.0.0:22122
  hash: fnv1a_64
  hash_tag: "{}"
  distribution: ketama
  auto_eject_hosts: false
  timeout: 400 
  redis: true
  servers:
   - 127.0.0.1:6380:1
   - 127.0.0.1:6381:1
   - 127.0.0.1:6382:1

配置檔案中各個引數的說明如下:

  • listen引數

配置twemproxy監聽的地址和埠。注意:每個服務池都需要配置一個監聽地址和埠。監聽的地址可以相同,但埠需要不同,這樣twemproxy才能區分不同的伺服器池。

從example.yml配置檔案中的listen引數可以看出,有兩個redis的伺服器池,這兩個伺服器池分別由監聽22122和22121的代理來服務。

  • client_connections

允許來自redis客戶端的最大連線數。預設情況下無限制,但作業系統施加的限制仍然存在。

  • hash

使用的hash函式的名字。可以是以下幾種:

函式名
md5
crc16
crc32
crc32a
fnv1_64
fnv1a_64
fnv1_32
fnv1a_32
hsieh
murmur
jenkins
  • hash_tag引數

由於key的分配非常重要,在使用叢集時,最好能讓key的分配可控性更強。

該引數可以讓key的分配可控性更強。若為該伺服器池配置了hash_tag,將會使用hash_tag之內的部分作為key分配的依據,否則會使用整個key的內容作為分配依據。

  • distribution

設定key分配演算法,可以有三種:

(1) ketama: 通過一致性hash演算法來選擇後端伺服器

(2) modula: 取模方式來選擇後端伺服器

(3) random: 隨機選擇一個後端伺服器池中的伺服器

  • timeout

我們等待建立與伺服器的連線或從伺服器接收響應的超時值(以毫秒為單位)。預設情況下會無限期地等待。

  • backlog

TCP listen的backlog引數。預設為512。

  • preconnect

一個布林值,用於控制在程序啟動時twemproxy是否應預先連線到此池中的所有伺服器。預設為false。

  • redis

一個布林值,用於控制伺服器池是否使用redis或memcached協議。預設為false。

  • redis_auth

在連線時對Redis伺服器進行身份驗證。

  • redis_db

要在池伺服器上使用的庫編號(redis中可以通過select命令來選擇資料庫)。預設為0.注意:Twemproxy將始終以庫 0的形式呈現給客戶端。

  • server_connections

可以開啟到每個伺服器的最大連線數。預設情況下,我們最多開啟1個伺服器連線。

  • auto_eject_hosts

一個布林值,用於控制伺服器在連續失敗server_failure_limit次數時是否應暫時去除。預設值為false

  • server_retry_timeout

當auto_eject_host設定為true時,在臨時彈出的伺服器上重試之前等待的超時值(以毫秒為單位)。預設為30000毫秒。

  • servers

此伺服器池的伺服器列表。格式如下:

 ip:port:weight  //ip地址:埠:權重

name:port:weight //主機名:埠:權重

系統初始化

系統初始化主要完成以下幾件事情:

  • (1) 初始化三個空閒佇列:空閒mbuf佇列,空閒msg佇列,空閒conn佇列
  • (2) 初始化伺服器池,若需要還要和後端服務建立連線
  • (3) 初始化伺服器key分配演算法,若選用一致性hash演算法,還需要構建伺服器的一致性hash環。
  • (4) 初始化事件處理框架,設定初始事件處理回撥函式
  • (5) 啟動事件處理框架

初始化空閒佇列

空閒佇列用來儲存不再使用的資料結構實體,比如:mbuf,msg,conn,這樣就可以複用這些結構體,再次使用時不需要再進行記憶體分配動作,從而提升了效能。

在twemproxy中會初始化三個空閒佇列:mbuf結構體,msg結構體,conn結構體。空閒佇列的初始化程式碼如下:

struct context *
core_start(struct instance *nci)
{
    struct context *ctx;

    mbuf_init(nci); // 初始化mbuf結構體空閒佇列
    msg_init(); //初始化msg結構體空閒佇列
    conn_init(); //初始化conn結構體空閒佇列
    ... ...
}
  • 初始化mbuf佇列

初始化mbuf空閒佇列相對簡單,主要是初始化靜態變數:

tatic struct mhdr free_mbufq;

並設定每次建立mbuf結構時的記憶體塊的size大小的變數:mbuf_chunk_size,該變數的預設值是:16k。

void
mbuf_init(struct instance *nci)
{
    nfree_mbufq = 0; //設定空閒佇列的mbuf結構體個數
    STAILQ_INIT(&free_mbufq); //初始化佇列

    mbuf_chunk_size = nci->mbuf_chunk_size;  //mbuf的chunk大小
    mbuf_offset = mbuf_chunk_size - MBUF_HSIZE; //mbuf的offset大小
    ... ...
}

free_mbufq初始化後的結構如下:

  • 初始化msg空閒佇列

初始化msg空閒佇列主要是初始化靜態變數:free_msgq。

static struct msg_tqh free_msgq;

msg空閒佇列初始化要完成以下事項:

(1) 設定msg佇列的個數變數nfree_msgq為0

static struct msg_tqh free_msgq;

(2) 初始化靜態變數free_msgq,該變數用來管理空閒佇列

(3) 初始化一顆紅黑樹,後面要用該結構來儲存msg的引用

初始化的程式碼如下:

void
msg_init(void)
{       
    ...
    msg_id = 0; //初始化msg_id,這是msg的計數器
    frag_id = 0; //初始化frag_id,這是fragment計數器
    nfree_msgq = 0; //初始化msg的個數為0
    TAILQ_INIT(&free_msgq); //初始化空閒msg佇列
    rbtree_init(&tmo_rbt, &tmo_rbs); //初始化超時紅黑樹
} 
  • 初始化conn空閒佇列

初始化conn空閒佇列很簡單,主要是初始化空閒conn佇列的個數,並初始化free_connq佇列。

static struct conn_tqh free_connq; 

初始化程式碼如下:

void
conn_init(void)
{
    ... ...  
    nfree_connq = 0;
    TAILQ_INIT(&free_connq); //初始化conn佇列
}

初始化伺服器池

若設定了preconnect引數為true,則會預先和後端伺服器池中的每個伺服器建立好連線。若按上面的伺服器池配置,會得到如下的連線圖:

上圖只是一個示意圖,實際上在ketama的這個一致性hash環中,還會存在多個虛擬的節點,會根據配置的權重來安排虛擬節點的個數,這些虛擬節點對應著圖中的三個實體節點。詳細的ketama演算法的實現,可以閱讀我的這篇文章:twemproxy0.4原理分析-一致性hash演算法實現ketama分析。示意圖如下:

設定事件處理函式

twemproxy0.4使用的事件驅動框架的入口都是相同的,只是不同的事件會呼叫不同的函式來處理。事件處理框架的函式呼叫流程如下:

總結

本文分析了twemproxy0.4的配置檔案和系統的初始化過程。

參考資料