用Bollger记录技术之路的点滴...

关注高性能linux网络编程,NoSQL, c/c++/java ~~~ weibo @语_行 http://weibo.com/201281062~~~ twitter @JerryVector https://twitter.com/JerryVector
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

twemproxy源码解析系列二----关键数据结构分析

Posted on 2013-03-16 22:25  语行  阅读(2600)  评论(0编辑  收藏  举报

三、Twemproxy关键数据结构分析

1:  array. 位于:nc_array.h

Twemproxy自己实现了一个数组结构以及一系列对这个结构进行操作的函数,array结构定义如下:

struct array {

    uint32_t nelem;  /* # element  当前数组的位置索引*/

    void     *elem;  /* element    元素指针,指向array的首地址*/

    size_t   size;   /* element size   每一个元素的大小 */

    uint32_t nalloc; /* # allocated element  数组可以分配的元素 */

};

 

其中需要注意的是size这个元素,它并不是指当前array的大小,而是指每一个elem的大小。这是一个非常重要的数据结构,后边在对配置文件做初始话的时候都需要用到它。

2: nc_conf.h中定义的一系列数据结构。

当我最开始看twemproxy的时候,对于它配置文件以及相应程序中对应数据结构的定义感觉很不好理解。因为twemproxy使用的是纯文本的配置,然后使用yaml对配置文件进行解析。

a:conf_listen  位于: nc_conf.h

struct conf_listen {
    struct string   pname;   /* listen: as "name:port" */
    struct string   name;    /* name */
    int             port;    /* port */
    struct sockinfo info;    /* listen socket info */
    unsigned        valid:1; /* valid? */
};

 

配置文件一个节点配置的twemproxy实例监听的port以及host的抽象

b:conf_server  位于:nc_conf.h

struct conf_server {
    struct string   pname;      /* server: as "name:port:weight" */
    struct string   name;       /* name */
    int             port;       /* port */
    int             weight;     /* weight */
    struct sockinfo info;       /* connect socket info */
    unsigned        valid:1;    /* valid? */
};

配置文件中一个节点配置的servers的抽象,即后端服务的host,port,weight

c:conf_pool  位于nc_conf.h

struct conf_pool {
    struct string      name;                  /* pool name (root node) */
    struct conf_listen listen;                /* listen: */
    hash_type_t        hash;                  /* hash: */
    struct string      hash_tag;              /* hash_tag: */
    dist_type_t        distribution;          /* distribution: */
    int                timeout;               /* timeout: */
    int                backlog;               /* backlog: */
    int                client_connections;    /* client_connections: */
    int                redis;                 /* redis: */
    int                preconnect;            /* preconnect: */
    int                auto_eject_hosts;      /* auto_eject_hosts: */
    int                server_connections;    /* server_connections: */
    int                server_retry_timeout;  /* server_retry_timeout: in msec */
    int                server_failure_limit;  /* server_failure_limit: */
    struct array       server;                /* servers: conf_server[] */
    unsigned           valid:1;               /* valid? */
};

conf_pool即配置文件中一个节点的抽象

 

d:conf  位于 nc_conf.h

struct conf {
    char          *fname;           /* file name (ref in argv[]) */
    FILE          *fh;              /* file handle */
    struct array  arg;              /* string[] (parsed {key, value} pairs) */
    struct array  pool;             /* conf_pool[] (parsed pools) */
    uint32_t      depth;            /* parsed tree depth */
    yaml_parser_t parser;           /* yaml parser */
    yaml_event_t  event;            /* yaml event */
    yaml_token_t  token;            /* yaml token */
    unsigned      seq:1;            /* sequence? */
    unsigned      valid_parser:1;   /* valid parser? */
    unsigned      valid_event:1;    /* valid event? */
    unsigned      valid_token:1;    /* valid token? */
    unsigned      sound:1;          /* sound? */
    unsigned      parsed:1;         /* parsed? */
    unsigned      valid:1;          /* valid? */
};

conf即配置文件的抽象。其中:

sound: 用于标识配置文件的格式是否正确。

parsed: 用于标识配置文件是否已经解析过了。

 

3:nc_conn.h中定义的数据结构

struct conn {
    TAILQ_ENTRY(conn)  conn_tqe;      /* link in server_pool / server / free q */
    /*
     * 标识一个连接的拥有者,对于proxy和client来说是struct seerver_pool,对于server来说,是struct server 
     */
    void               *owner;        /* connection owner - server_pool / server   */  
    int                sd;            /* socket descriptor */
    int                family;        /* socket address family */
    socklen_t          addrlen;       /* socket length */
    struct sockaddr    *addr;         /* socket address (ref in server or server_pool) */
    struct msg_tqh     imsg_q;        /* incoming request Q 进来的请求 */
    struct msg_tqh     omsg_q;        /* outstanding request Q 未完成的请求 */
    struct msg         *rmsg;         /* current message being rcvd */
    struct msg         *smsg;         /* current message being sent */
    conn_recv_t        recv;          /* recv (read) handler sd上读事件发生时的回调函数*/
    conn_recv_next_t   recv_next;     /* recv next message handler */
    conn_recv_done_t   recv_done;     /* read done handler */
    conn_send_t        send;          /* send (write) handler sd上写事件发生时的回调函数*/
    conn_send_next_t   send_next;     /* write next message handler */
    conn_send_done_t   send_done;     /* write done handler */
    conn_close_t       close;         /* close handler */
    conn_active_t      active;        /* active? handler */
    conn_ref_t         ref;           /* connection reference handler */
    conn_unref_t       unref;         /* connection unreference handler */
    conn_msgq_t        enqueue_inq;   /* connection inq msg enqueue handler */
    conn_msgq_t        dequeue_inq;   /* connection inq msg dequeue handler */
    conn_msgq_t        enqueue_outq;  /* connection outq msg enqueue handler */
    conn_msgq_t        dequeue_outq;  /* connection outq msg dequeue handler */
    size_t             recv_bytes;    /* received (read) bytes */
    size_t             send_bytes;    /* sent (written) bytes */
    uint32_t           events;        /* connection io events */
    err_t              err;           /* connection errno */
    unsigned           recv_active:1; /* recv active? */
    unsigned           recv_ready:1;  /* recv ready? */
    unsigned           send_active:1; /* send active? */
    unsigned           send_ready:1;  /* send ready? */
    unsigned           client:1;      /* client? or server? */
    unsigned           proxy:1;       /* proxy? */
    unsigned           connecting:1;  /* connecting? */
    unsigned           connected:1;   /* connected? */
    unsigned           eof:1;         /* eof? aka passive close? */
    unsigned           done:1;        /* done? aka close? */
    unsigned           redis:1;       /* redis? */
};

conn是twemproxy一个非常重要的结构,客户端到twemproxy的连接以及twemproxy到后端server的连接,以及proxy本身监听的tcp端口都可以抽象为一个conn。同时对于一个conn来说,也有不同的种类,例如:客户端到proxy的连接conn就属于一个”client”, proxy到后端server的连接就属于”server”, 而proxy本身监听的端口所在的tcp套接字,就属于“proxy”。

client:这个元素标识这个conn是一个client还是一个server。

proxy:这个元素标识这个conn是否是一个proxy。

owner:这个元素标识这个conn的属主。

纵观twemproxy, 他里边的conn有三种,client, server, proxy。当这个conn     是一个proxy或者client时,则它此时的owner就是server_pool; 而当这  个conn是一个server时,则它此时的owner就是server

sd:   这个conn包含的socket描述符。

conn还包含有很多函数指针,都是在对应事件发生时调用的回调函数,这些在具体分析请求处理的时候在做说明。

 

4: nc_server.h中定义的一系列数据结构

a:

struct server_pool {
    uint32_t           idx;                  /* pool index */
    struct context     *ctx;                 /* owner context */
    struct conn        *p_conn;              /* proxy connection (listener) */
    uint32_t           nc_conn_q;            /* # client connection */
    struct conn_tqh    c_conn_q;             /* client connection q */
    struct array       server;               /* server[] */
    uint32_t           ncontinuum;           /* # continuum points */
    uint32_t           nserver_continuum;    /* # servers - live and dead on continuum (const) */
    struct continuum   *continuum;           /* continuum */
    uint32_t           nlive_server;         /* # live server */
    int64_t            next_rebuild;         /* next distribution rebuild time in usec */
    struct string      name;                 /* pool name (ref in conf_pool) */
    struct string      addrstr;              /* pool address (ref in conf_pool) */
    uint16_t           port;                 /* port */
    int                family;               /* socket family */
    socklen_t          addrlen;              /* socket length */
    struct sockaddr    *addr;                /* socket address (ref in conf_pool) */
    int                dist_type;            /* distribution type (dist_type_t) */
    int                key_hash_type;        /* key hash type (hash_type_t) */
    hash_t             key_hash;             /* key hasher */
    struct string      hash_tag;             /* key hash tag (ref in conf_pool) */
    int                timeout;              /* timeout in msec */
    int                backlog;              /* listen backlog */
    uint32_t           client_connections;   /* maximum # client connection */
    uint32_t           server_connections;   /* maximum # server connection */
    int64_t            server_retry_timeout; /* server retry timeout in usec */
    uint32_t           server_failure_limit; /* server failure limit */
    unsigned           auto_eject_hosts:1;   /* auto_eject_hosts? */
    unsigned           preconnect:1;         /* preconnect? */
    unsigned           redis:1;              /* redis? */
};

server_pool: 配置文件中每一个节点配置的servers的一个抽象。

redis : 标识是否是redis的代理

dist_type: 数据分片类型

 

b:

struct server {
    uint32_t           idx;           /* server index */
    struct server_pool *owner;        /* owner pool */

    struct string      pname;         /* name:port:weight (ref in conf_server) */
    struct string      name;          /* name (ref in conf_server) */
    uint16_t           port;          /* port */
    uint32_t           weight;        /* weight */
    int                family;        /* socket family */
    socklen_t          addrlen;       /* socket length */
    struct sockaddr    *addr;         /* socket address (ref in conf_server) */

    uint32_t           ns_conn_q;     /* # server connection */
    struct conn_tqh    s_conn_q;      /* server connection q */

    int64_t            next_retry;    /* next retry time in usec */
    uint32_t           failure_count; /* # consecutive failures */
};

 

server即配置文件中一个节点配置的servers中一个server的抽象。其中:

owner:标识这个server属于哪个server_pool

ns_conn_q:标识到这个后端server的连接数

s_conn_q:标识到这个server所有的conn(conn是twemproxy中很关键的一个数据结构,标识一个连接,下边介绍)。注意这个属性维持的是一个队列(队列使用的是Freebsd中提供的一个队列实现:queue.h;libevent也使用这个队列实现)。