Twemproxy源码分析(五)配置文件

23 篇文章 0 订阅
5 篇文章 0 订阅

概述:

Twemproxy使用yaml作为配置文件的格式,本节我们看一下Twemproxy如何读取配置文件的,如果要扩展Twemproxy的功能,修改配置是必不可少的。

配置加载:

前面我们提到,instance结构中,有个conf_filename字段,这个字段存放的就是配置文件名,于是我们通过这个字段查找一下Twemproxy是在什么地方加载的配置文件:

可见,加载conf_filename使用的是conf_create函数,这个函数在nc_conf.c中定义:

载入的步骤很简单:

  1. open
  2. pre_validate
  3. parse
  4. post_validate
  5. dump

我整理了一个图,来稍微看一下conf_create的细节:

conf_create

其中从左指向右的箭头是调用关系,从上指向下的箭头是调用先后顺序,圆圈代表循环。可以看到conf_parse包括了conf_begin_parse、conf_parse_core和conf_end_parse三个步骤,begin和end是相互对应的,conf_parse_core还没有展开细节,我们后面再细看。

conf_create函数返回一个conf结构体,这个结构体的定义在nc_conf.h中:

每个字段含义见注释,其中arg和pool都是前面介绍的array类型。接下来我们具体看一下上面几个比较重要函数:conf_open、conf_begin_parse、conf_parse_core、conf_end_parse。

conf_open:

conf_create通过conf_open函数创建conf,conf_open函数定义如下:

可以看出conf_open做了以下几件事:

  • 打开配置文件
  • 创建conf
  • 初始化cf->arg和cf_pool这两个数组,分别存放string和conf_pool
  • 初始化cf其他各字段

创建了conf之后,便是进行conf_pre_validate、conf_parse然后是conf_post_validate。pre_validate和post_validate都是对配置进行校验,具体怎么校验的我们暂不细看了,我们主要看parse的部分,在深入了解parse的逻辑之前,我们要先来了解一下twemproxy使用的libyaml。

libyaml:

Twemproxy用到了libyaml来解析yaml格式的配置文件,并将libyaml-0.1.4的代码放在contrib目录下。libyaml包括了两个主要功能:yaml文件的解析和生成(称为parser和emitter)。这两个功能是可以完全互斥的,也就是说parser解析出来的event序列,可以交给emitter生成相同格式的yaml文件,反过来也是一样。

刚才提到了event序列,parser解析yaml文件时,产生event序列,event包含以下类型:

  • STREAM-START
  • STREAM-END
  • DOCUMENT-START
  • DOCUMENT-END
  • ALIAS
  • SCALAR
  • SEQUENCE-START
  • SEQUENCE-END
  • MAPPING-START
  • MAPPING-END

每个event产生时,根据不同的类型,还会有不同的attribute,具体这里不做赘述,感兴趣的可以看一下libyaml的文档。

event产生的序列,应该符合这样的语法描述:

那么解析一个yaml文档的步骤大概是这样的:

  1. 调用yaml_parser_initialize,生成一个parser
  2. 调用yaml_parser_set_input_file,为parser制定yaml文件的handle。或者调用yaml_parser_set_input_string指定文件内容也行。
  3. 调用yaml_parser_parse,产生一个event,根据event的type和attribute进行处理
  4. 调用yaml_event_delete销毁刚刚产生的event,回到第3步获得下一个event,直到所有event处理完
  5. 调用yaml_parser_delete销毁parser

通过这个图可以很容易理解:

yaml

 

为了更好的理解yaml解析的过程,我写了个简单的程序:

程序的作用就是调用libyaml解析一个yaml文件,并将产生的event序列输出,使用的yaml文件是Twemproxy默认的配置文件,内容如下:

程序执行产生的输出如下:

具体是怎么个逻辑就不解释了,大家自己理解就好了。

大概了解了libyaml之后,我们可以继续了解conf_parse了。

conf_begin_parse、conf_end_parse:

前面我们提到,begin_parse和end_parse是一对相互对应函数,我们看下他们具体做了什么:

begin_parse创建了parser,然后循环处理并且忽略掉了parser产生的MAPPING_START之前的event(还包括MAPPING_START本身)。

end_parse是和begin_parse对应的,忽略掉STREAM_END之前的所有event(包括STREAM_END)。可见,begin_parse和end_parse的作用是忽略掉除mapping以外的部分。

conf_parse_core:

conf_parse_core是解析配置文件的主要逻辑,它是一个递归函数,在了解conf_parse_core之前,我们要先看一下conf_push_scalar和conf_pop_scalar函数的作用:

可以看到, conf_push_scalar的作用,是将scalar event的值(一个字符串),压入cf->arg数组中。

conf_pop_scalar的作用是从cf->arg数组中pop一个元素出来,然后丢弃这个元素。好了,接下来我们就看conf_parse_core

单独看代码,和注释,不是很容易理解,我先解释一下这里面的几个概念:

  1. depth:一层mapping对应一个depth,前面我们看到了,ROOT的层级是1,这个层级上的每一个node,都代表一个pool。在第一次调用core_parse_core的时候,depth == 1,这个时候会向cf->pool压入一个pool,并将标记new_pool置为1。
  2. leaf:有两个条件情况会导致leaf == true,一个是在sequence中(Twemproxy配置文件sequence下不再有map了),另一个是cf->arg中元素数量 == depth + 1,这个如何理解呢,看下面这个图,灰色部分是leaf:depth
  3. done:只有depth==1层级处理结束,done才为1,这也是递归的退出条件。

基本上这个函数逻辑是这样的:

  1. 最外层depth == 1,得到的scalar的value是这个pool的name,于是创建一个新的pool、压入cf->pool、置new_pool为1,然后递归调用conf_parse_core。
  2. 每遇到一个mapping,则depth++,离开mapping的时候depth–
  3. 每遇到sequence的时候置cf->seq = 1,离开时置cf->seq = 0
  4. 每遇到一个scalar,将它压入cf->arg
  5. 如果是leaf,或者new_pool,则调用conf_handler,创建/修改pool的配置
  6. 最后将处理完的scalar弹出,seq弹出1个(value),否则弹出2个(key和value)
  7. 递归调用conf_parse_core

OK,那么可以看到,在遇到scalar的时候,都是先压入cf->arg,这个认为是临时存放配置项的地方。那么每次遇到leaf的时候(上图灰色部分),则需要调用conf_handler来处理,那么这个函数做了什么呢?

看到这里就比较清楚了,当new_pool的情况下调用conf_pool_init初始化这个conf_pool,其他情况则设置conf_pool实例中的具体字段值。conf_commands中定义了twemproxy配置所接受的所有command,以及他们的set函数指针,这个通过command的定义可以看出:

不同的配置项,可能有专属的set函数,这个通过定义conf_commands数组来指定。

至此Twemproxy加载和解析配置文件的过程就分析完了。

小结:

本节内容较多,不过不用担心,nc_conf是Twemproxy里面代码最多的模块了,后面的都会简单些。本节主要分析了配置文件加载和解析的过程,其中涉及到了libyaml,以及一些重要的数据结构如conf_pool、conf等,配置的验证validate则没有分析,目前不太涉及到,就偷个懒吧。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值