bfe业余分析(三)

简单分析下配置reload的逻辑。bfe中配置的加载分为主配置和模块配置。

模块配置

bfe_modules/mod_block为例。触发的web请求为/reload/mod_block.product_rule_table, /reload/mod_block.global_ip_table

简单逻辑就是注册对应的reload的handler, 当出现对应的web请求时, 重新读取配置文件,生成对应的数据然后替换当前模块的配置。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
type ModuleBlock struct {
    name    string           // name of module
    state   ModuleBlockState // module state
    metrics metrics.Metrics

    productRulePath string // path of block rule data file
    ipBlacklistPath string // path of ip blacklist data file

/*
    下面是对应的配置
*/

    ruleTable *ProductRuleTable // table for product block rules
    ipTable   *ipdict.IPTable   // table for global ip blacklist
}

....

/*
    reload配置注册
*/
func (m *ModuleBlock) reloadHandlers() map[string]interface{} {
    handlers := map[string]interface{}{
        m.name + ".global_ip_table":    m.loadGlobalIPTable,
        m.name + ".product_rule_table": m.loadProductRuleConf,
    }
    return handlers
}

....

/*
    看一下其中一个函数
*/

// loadProductRuleConf load from config file.
func (m *ModuleBlock) loadProductRuleConf(query url.Values) error {
    // get path
    path := query.Get("path")
    if path == "" {
        // use default
        path = m.productRulePath
    }

    // load file
    conf, err := ProductRuleConfLoad(path)
    if err != nil {
        return fmt.Errorf("err in ProductRuleConfLoad(%s):%s", path, err)
    }

/*
    里面就是加锁替换变量, 加锁原因是主流程会一直去查询这个变量
*/

    m.ruleTable.Update(conf)
    return nil
}


/*
    请求处理逻辑
*/

// productBlockHandler is a handler for doing product block.
func (m *ModuleBlock) productBlockHandler(request *bfe_basic.Request) (
    int, *bfe_http.Response) {
    if openDebug {
        log.Logger.Debug("%s check request", m.name)
    }
    m.state.ReqTotal.Inc(1)

    // find block rules for given request
    /* 这里会加锁 */
    rules, ok := m.ruleTable.Search(request.Route.Product)
    if !ok { // no rules found
        if openDebug {
            log.Logger.Debug("%s product %s not found, just pass",
                m.name, request.Route.Product)
        }
        return bfe_module.BfeHandlerGoOn, nil
    }

    m.state.ReqToCheck.Inc(1)
    return m.productRulesProcess(request, rules)
}

这块是全量加载

主配置

这里主要看下product的配置reload。

先看web入口函数(bfe_server/web_server.go)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// reloadHandlers holds all reload handlers.
func (m *BfeMonitor) reloadHandlers() map[string]interface{} {
    handlers := map[string]interface{}{
        // for server data conf
        "server_data_conf": m.srv.ServerDataConfReload,

        // for gslb data conf
        "gslb_data_conf": m.srv.GslbDataConfReload,

        // for name conf
        "name_conf": m.srv.NameConfReload,

        // for tls
        "tls_conf":               m.srv.TLSConfReload,
        "tls_session_ticket_key": m.srv.SessionTicketKeyReload,
    }
    return handlers
}

然后顺着看下对应的函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// ServerDataConfReload reloads host/route/cluster conf
func (srv *BfeServer) ServerDataConfReload(query url.Values) error {
    hostFile := srv.Config.Server.HostRuleConf
    vipFile := srv.Config.Server.VipRuleConf
    routeFile := srv.Config.Server.RouteRuleConf
    clusterConfFile := srv.Config.Server.ClusterConf

    path := query.Get("path")
    if path != "" {
        hostFile = joinPath(path, hostFile)
        vipFile = joinPath(path, vipFile)
        routeFile = joinPath(path, routeFile)
        clusterConfFile = joinPath(path, clusterConfFile)
    }

    return srv.serverDataConfReload(hostFile, vipFile, routeFile, clusterConfFile)
}

func (srv *BfeServer) serverDataConfReload(hostFile, vipFile, routeFile, clusterConfFile string) error {
    newServerConf, err := bfe_route.LoadServerDataConf(hostFile, vipFile, routeFile, clusterConfFile)
    if err != nil {
        log.Logger.Error("ServerDataConfReload():bfe_route.LoadServerDataConf: %s", err)
        return err
    }

/*
    这里更新配置
*/

    srv.confLock.Lock()
    srv.ServerConf = newServerConf
    srv.confLock.Unlock()

    srv.ReverseProxy.setTransports(srv.ServerConf.ClusterTable.ClusterMap())

    // set gslb basic
    srv.balTable.SetGslbBasic(newServerConf.ClusterTable)

    return nil
}

这段server配置使用时,是在生成request变量时直接赋值给它(bfe_server/http_conn.go)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// Read next request from connection.
func (c *conn) readRequest() (request *bfe_basic.Request, err error) {
    c.lr.N = int64(c.server.MaxHeaderBytes) + 4096 /* bufio slop */

    var req *bfe_http.Request

    // another request arrives
    c.reqSN += 1
    if req, err = bfe_http.ReadRequest(c.buf.Reader, c.server.MaxHeaderUriBytes); err != nil {
        if c.lr.N == 0 {
            return nil, errTooLarge
        }
        return nil, err
    }
    c.lr.N = noLimit

    req.RemoteAddr = c.remoteAddr
    req.State.SerialNumber = c.reqSN
    req.State.Conn = c.rwc

    reqStat := bfe_basic.NewRequestStat(req.State.StartTime)
    reqStat.ReadReqEnd = time.Now()
    reqStat.HeaderLenIn = int(req.State.HeaderSize)

/*
    获取对应的server配置, 然后生成request。后续在查找host对应的product时直接使用该配置
*/
    sf := c.server.GetServerConf()

    return bfe_basic.NewRequest(req, c.rwc, reqStat, c.session, sf), nil
}

/*
    安全的获取
*/
func (s *BfeServer) GetServerConf() *bfe_route.ServerDataConf {
    s.confLock.RLock()
    sf := s.ServerConf
    s.confLock.RUnlock()

    return sf
}