BFE初探

Wesley13
• 阅读 505

项目简介

BFE是一个开源的七层负载均衡系统,和Nginx功能类似,但是比Nginx多了集群负载均衡功能、转发规则使用的是条件表达式(类似于表达式求值功能,Nginx使用的是正则表达式),提供了丰富的内部状态展示统计信息等。详情 

功能组件

BFE包含了多个组件,部分是可选的:

  • BFE Server: BFE数据平面核心转发模块(必选,已开源)

  • BFE-Reader: BFE日志分析模块,与BFE Server部署在一起,用于对BFE日志进行本地汇聚计算,降低后续计算处理的数据规模。

  • BFE-API Server: BFE控制平面API Server,其它控制平面模块以BFE-API Server为核心协同工作。

  • BFE-Aggregator: BFE日志数据实时聚合计算模块。

  • BFE-Scheduler: BFE流量调度器,基于流量、容量、网络距离及质量,自动计算全局负载均衡(GSLB)策略。

  • BFE-Controller: BFE集群控制器,执行常规控制任务,例如异常巡检及报警。

  • BFE-Web UI: BFE Web控制台。

  • 其它周边依赖系统, 例如缓存服务、非对称密码学算法计算服务等。

在上述组件中,只有 BFE-Server开源了,其他都尚未开源。

概念说明

产品线:Product,也被成为“租户”。BFE的配置,比如转发策略、权限等,是已产品线为单位来进行设置
集   群:Cluster,把具有同类功能的后端集合定义成为一个集群
子集群:Subcluster,集群又可细分成多个子集群,通常把处于同一个IDC的后端定义为子集群
实    例:Instance,每个子集群可包含多个后端服务实例,每个后端实例通过“IP地址+端口号”标识

比如:外卖产品线有多个服务集群(用户端、商家端、管理端等),其中用户端集群有N个子集群(DX,YF集群),每个子集群里面有多个服务实例

流量接入转发说明

BFE初探

  • Step 1-2:DNS解析

    • 请求的域名为 demo.example.com
    • 返回IP地址为 6.6.6.6(示例地址)
  • Step 3:用户与 6.6.6.6:80 建立TCP连接并发送HTTP请求,IP报文被路由到IDC1的入口,由四层负载均衡设施处理

  • Step 4:四层负载均衡设施将报文转发给下游BFE

  • Step 5:BFE收到HTTP请求, 确定处理该请求的产品线

    • BFE根据HTTP请求头中的Host字段, 确定产品线
    • 对于demo.example.com域名,假设对应的产品线名为demo
  • Step 6:BFE根据产品线的分流规则,选择该请求的目的集群

    • 对于这个请求,假设对应的目的集群为demo-static
    • 详见基于内容路由说明
  • Step 7-8:BFE根据产品线的均衡策略,选择子集群及实例

    • 对于这个请求,假设子集群为demo-static.idc1,实例为demo-static-01.idc1
    • 详见流量负载均衡说明
  • Step 9:请求被发往后端实例demo-static-01.idc1

  • Step 10:BFE收到后端实例回复的响应

  • Step 11-12:BFE通过四层负载均衡设施,将响应返回给用户

路由规则

根据流量接入转发模型中的流程,服务路由流程如下:

  • BFE根据HTTP请求头中的Host字段, 确定产品线
  • 根据产品线的分流规则,选择该请求的目的集群
  • 根据均衡策略,把请求转到具体的某个 子集群及实例 并把处理后的结果返回

示例

用户请求 demo.example.com,BFE根据HTTP请求中的Host字段,确定产品线为:demo

  • 产品线demo,包含以下3种服务集群:
    • 静态集群(demo-static):服务静态流量
    • post集群(demo-post):服务post流量
    • main集群(demo-main):服务其他流量
  • 期望的转发条件如下:
    • 对于path以"/static"为前缀的,都发往demo-static集群
    • 请求方法为"POST"、且path以"/setting"为前缀的,都发往demo-post
    • 其它请求,都发往demo-main
  • 对应以上要求,产品线demo的转发表如下图所示

BFE初探

负载均衡规则 

如何把流量均衡分配到集群中的多个子集群及其内部的实例?这个需求在多IDC场景中非常常见。 详情

另外,为了防止集群整体过载,也可以使用虚拟黑洞集群来主动丢弃(Blackhole)。

实现策略:

  • 设置子集群权重(分流比例),BFE根据配置设做加权轮询调度(WRR),把服务指向子集群;
  • 通一子集群内的多个实例之间,支持多种负载均衡算法:WRR加权轮询、WLC加权最小连接数,支持根据实例处理能力不同设置不同的权重。

健康检测:BFE为每个服务实例维护一个状态机,正常状态或不可用状态,对不可用状态亦会不断进行检测直至恢复可用。

失败重试机制:支持同子集群重试、跨子集群重试

连接池:支持短连接、连接池方式

会话保持:支持将相同来源请求转发至固定的业务后端(某个子集群或某个实例)

Quick Start

配置组织

BFE的核心配置是bfe.conf (conf/bfe.conf),为便于维护, 配置按功能分类存放在相应目录 conf//

功能类别

文件位置

描述

服务基础配置

conf/bfe.conf

定义服务监听端口、超时时间、模块、session等

接入协议配置

conf/tls_conf/ 目录

密钥,协议支持等

流量路由配置

conf/server_data_conf/ 目录

host_rule.data:产品线域名表配置文件

vip规则、路由规则等

负载均衡配置

conf/cluster_conf/ 目录

 

扩展模块配置

conf/mod_ 目录

 

说明:

1.产品线域名表配置文件 : conf / server_data_conf / host_rule.data 

目的:实现企业多域名都指向同一product的需求,比如: abc.com / abc.cn 都由 productX 提供服务。

{
    "Version": "init version",
    "DefaultProduct": null,
    "Hosts": { //域名标签和域名列表的映射关系表
        "exampleTag1":[ //域名标签
            "example1.org" //域名列表
            "example2.org"
        ],
        "exampleTag2":[
            "xxx.org"
            "zzz.org"
        ]
    },
    "HostTags": { //产品线和域名标签的映射关系
        "example_product1":[ //产品线名称
            "exampleTag1" //域名标签列表
        ],
        "product2":[
            "exampleTag2"
        ]
    }
}

2.VIP规则配置文件 : conf / server_data_conf / vip_rule.data 

目的:vip_rule和host_rule类似,host_rule是通过域名路由到product;vip_rule通过请求来源的IP路由到product,vip_rule在host_rule失败时生效。在百度内部,BFE的前面是四层负载均衡,每个产品线一般都有固定的vip,所以vip也可以起到像域名一样的路由作用。

{
    "Version": "init version",
    "Vips": { //各产品线的VIP列表
        "example_product": [ //产品线名称
            "111.111.111.111" //VIP列表
        ] 
    }
}

3.路由分流配置文件:conf / server_data_conf / router_rule.data

目的:根据规则把请求路由到具体的集群

{
    "Version": "init version",
    "ProductRule": { //各产品线的分流规则配置
        "example_product": [ //产品线名称
            {
                "Cond": "req_host_in(\"example.org\")", //分流条件, 语法详见Condition
                "ClusterName": "cluster_example"  //目的集群
            },
            {
                "Cond": "default_t()",
                "ClusterName": "cluster_example"
            }
        ]
    }
}

4.集群转发规则配置文件:conf / server_data_conf / cluster_conf.data

目的:根据规则把请求路由到具体的集群

{
    "Version": "init version",
    "Config": {
        "cluster_example": { //集群名称
            "BackendConf": { //后端基础配置
                "TimeoutConnSrv": 2000, //连接后端的超时时间,单位是毫秒,默认值2
                "TimeoutResponseHeader": 50000, //从后端读响应头的超时时间,单位是毫秒,默认值60
                "MaxIdleConnsPerHost": 0, //BFE实例与每个后端的最大空闲长连接数,默认值2
                "RetryLevel": 0 //请求重试级别。0:连接后端失败时,进行重试;1:连接后端失败、转发GET请求失败时均进行重试,默认值0
            },
            "CheckConf": { //健康检查配置
                "Schem": "http", //健康检查协议,支持HTTP和TCP,默认值 HTTP
                "Uri": "/healthcheck",//健康检查请求URI (仅HTTP),默认值 /health_check
                "Host": "example.org", //健康检查请求HOST (仅HTTP),默认值 ""
                "StatusCode": 200, //期待返回的响应状态码 (仅HTTP),默认值 0,代表任意状态码
                "FailNum": 10, //健康检查启动阈值(转发请求连续失败FailNum次后,将后端实例置为不可用状态,并启动健康检查),默认值5
                "SuccNum": 5, //健康检查成功阈值(健康检查连续成功SuccNum次后,将后端实例置为可用状态),默认值1
                "CheckTimeout":500,//健康检查的超时时间,单位是毫秒,默认值0(无超时)
                "CheckInterval": 1000 //健康检查的间隔时间,单位是毫秒,默认值1
            },
            "GslbBasic": { //GSLB基础配置
                "CrossRetry": 0, //跨子集群最大重试次数,默认值0
                "RetryMax": 2, //子集群内最大重试次,默认值2
                "BalanceMode":"WRR", //负载均衡模式(WRR: 加权轮询; WLC: 加权最小连接数),默认值WRR
                "HashConf": { //会话保持的HASH策略配置
                    "HashStrategy": 0, //会话保持的哈希策(ClientIdOnly, ClientIpOnly, ClientIdPreferred),默认值ClientIpOnly
                    "HashHeader": "Cookie:UID", //会话保持的hash请求头
                    "SessionSticky": false, //是否开启会话保持(开启后,可以保证来源于同一个用户的请求可以发送到同一个后端),默认值false
                }
            },
            "ClusterBasic": { //集群基础配置
                "TimeoutReadClient": 30000, //读用户请求wody的超时时间,单位为毫秒,默认值30
                "TimeoutWriteClient": 60000, //写响应的超时时间,单位为毫秒,默认值60
                "TimeoutReadClientAgain": 30000,//连接闲置超时时间,单位为毫秒,默认值60
                "ReqWriteBufferSize": 512, //Write buffer size for request in byte
                "ReqFlushInterval": 0,//Interval to flush request in ms. if zero, disable periodic flush
                "ResFlushInterval": -1,//Interval to flush response in ms. if zero, disable periodic flush
                "CancelOnClientClose": false //Cancel blocking operation on server if client connection disconnected
            }
        }
    }
}

5.负载均衡

  • 子集群负载均衡则配置文件:conf / cluster_conf / gslb.data

目的:各集群集群内的多个子集群直接分流比例(GSLB)

{
    "Hostname": "", //配置文件生成来源信息
    "Ts": "0", //配置文件生成的时间戳
    "Clusters": { //各集群中子集群的分流权重
        "cluster_example": { //集群名称
            "GSLB_BLACKHOLE": 0, //GSLB_BLACKHOLE(保留,黑洞子集群),分配到该子集群的流量将被丢弃,用于过载保护, 0代表权重(不参与流量任务),子集群分流权重之和应等于 100
            "example.bfe.bj": 100 // 子集群名 -> 子集群承接流量的权重
        }
    }
}
  • 实例负载均衡则配置文件:conf / cluster_conf / cluster_table.data

目的:记录各后端集群包含的子集群及实例

{
    "Version": "init version",
    "Config": { //各集群信息配置
        "cluster_example": { //集群名称
            "example.bfe.bj": [ //子集群名称
                { //子集群配置信息,包含多个实例配置
                    "Addr": "10.199.189.26", //实例监听地址
                    "Name": "example_hostname", //机器名称
                    "Port": 8181, //实例监听端口
                    "Weight": 10 //实例名称
                }
            ]
        }
    }
}

6.名字规则配置文件:conf / server_data_conf / name_conf.data

目的:记录服务名字和服务实例的映射关系。BFE很多配置用的是bns(一种名字服务,一个名字可以解析为一组服务实例的ip和端口,权重)。name.conf可以配置本地的名字

{
    "Version": "init version",
    "Config": { //名字和实例的映射关系
        "example.redis.cluster": [ //集群名称
            { //实例信息
                "Host": "192.168.1.1", //实例地址
                "Port": 6439, //实例端口
                "Weight": 10 //实例权重
            }
        ]
    }
}
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
2年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这