在nginx里,Upstream代表了反向代理的负载均衡配置。在这里,我们扩充Upstream的含义,让其具备以下几个特点:
Upstream和域名DNS解析都可以将一组ip配置到一个Host,但是
这是一个本地反向代理模块,代理配置对server和client都生效。
支持动态配置,可用于服务发现系统,目前workflow-k8s可以对接Kubernetes的API Server。
Upstream名不包括端口,但Upstream请求支持指定端口(如果使用非内置协议,Upstream名暂时需要加上端口号以保证构造时的解析成功)。
每一个Upstream配置自己的独立名称UpstreamName,并添加设定着一组Address,这些Address可以是:
class UpstreamManager
{
public:
static int upstream_create_consistent_hash(const std::string& name,
upstream_route_t consitent_hash);
static int upstream_create_weighted_random(const std::string& name,
bool try_another);
static int upstream_create_manual(const std::string& name,
upstream_route_t select,
bool try_another,
upstream_route_t consitent_hash);
static int upstream_create_vnswrr(const std::string& name);
static int upstream_delete(const std::string& name);
public:
static int upstream_add_server(const std::string& name,
const std::string& address);
static int upstream_add_server(const std::string& name,
const std::string& address,
const struct AddressParams *address_params);
static int upstream_remove_server(const std::string& name,
const std::string& address);
...
}
配置一个本地反向代理,将本地发出的my_proxy.name所有请求均匀的打到6个目标server上
UpstreamManager::upstream_create_weighted_random(
"my_proxy.name",
true);//如果遇到熔断机器,再次尝试直至找到可用或全部熔断
UpstreamManager::upstream_add_server("my_proxy.name", "192.168.2.100:8081");
UpstreamManager::upstream_add_server("my_proxy.name", "192.168.2.100:8082");
UpstreamManager::upstream_add_server("my_proxy.name", "192.168.10.10");
UpstreamManager::upstream_add_server("my_proxy.name", "test.sogou.com:8080");
UpstreamManager::upstream_add_server("my_proxy.name", "abc.sogou.com");
UpstreamManager::upstream_add_server("my_proxy.name", "abc.sogou.com");
UpstreamManager::upstream_add_server("my_proxy.name", "/dev/unix_domain_scoket_sample");
auto *http_task = WFTaskFactory::create_http_task("http://my_proxy.name/somepath?a=10", 0, 0, nullptr);
http_task->start();
基本原理
配置一个本地反向代理,将本地发出的weighted.random所有请求按照5/20/1的权重分配打到3个目标server上
UpstreamManager::upstream_create_weighted_random(
"weighted.random",
false);//如果遇到熔断机器,不再尝试,这种情况下此次请求必定失败
AddressParams address_params = ADDRESS_PARAMS_DEFAULT;
address_params.weight = 5;//权重为5
UpstreamManager::upstream_add_server("weighted.random", "192.168.2.100:8081", &address_params);//权重5
address_params.weight = 20;//权重为20
UpstreamManager::upstream_add_server("weighted.random", "192.168.2.100:8082", &address_params);//权重20
UpstreamManager::upstream_add_server("weighted.random", "abc.sogou.com");//权重1
auto *http_task = WFTaskFactory::create_http_task("http://weighted.random:9090", 0, 0, nullptr);
http_task->start();
基本原理
UpstreamManager::upstream_create_consistent_hash(
"abc.local",
nullptr);//nullptr代表使用框架默认的一致性哈希函数
UpstreamManager::upstream_add_server("abc.local", "192.168.2.100:8081");
UpstreamManager::upstream_add_server("abc.local", "192.168.2.100:8082");
UpstreamManager::upstream_add_server("abc.local", "192.168.10.10");
UpstreamManager::upstream_add_server("abc.local", "test.sogou.com:8080");
UpstreamManager::upstream_add_server("abc.local", "abc.sogou.com");
auto *http_task = WFTaskFactory::create_http_task("http://abc.local/service/method", 0, 0, nullptr);
http_task->start();
基本原理
UpstreamManager::upstream_create_consistent_hash(
"abc.local",
[](const char *path, const char *query, const char *fragment) -> unsigned int {
unsigned int hash = 0;
while (*path)
hash = (hash * 131) + (*path++);
while (*query)
hash = (hash * 131) + (*query++);
while (*fragment)
hash = (hash * 131) + (*fragment++);
return hash;
});
UpstreamManager::upstream_add_server("abc.local", "192.168.2.100:8081");
UpstreamManager::upstream_add_server("abc.local", "192.168.2.100:8082");
UpstreamManager::upstream_add_server("abc.local", "192.168.10.10");
UpstreamManager::upstream_add_server("abc.local", "test.sogou.com:8080");
UpstreamManager::upstream_add_server("abc.local", "abc.sogou.com");
auto *http_task = WFTaskFactory::create_http_task("http://abc.local/sompath?a=1#flag100", 0, 0, nullptr);
http_task->start();
基本原理
UpstreamManager::upstream_create_manual(
"xyz.cdn",
[](const char *path, const char *query, const char *fragment) -> unsigned int {
return atoi(fragment);
},
true,//如果选择到已经熔断的目标,将进行二次选取
nullptr);//nullptr代表二次选取时使用框架默认的一致性哈希函数
UpstreamManager::upstream_add_server("xyz.cdn", "192.168.2.100:8081");
UpstreamManager::upstream_add_server("xyz.cdn", "192.168.2.100:8082");
UpstreamManager::upstream_add_server("xyz.cdn", "192.168.10.10");
UpstreamManager::upstream_add_server("xyz.cdn", "test.sogou.com:8080");
UpstreamManager::upstream_add_server("xyz.cdn", "abc.sogou.com");
auto *http_task = WFTaskFactory::create_http_task("http://xyz.cdn/sompath?key=somename#3", 0, 0, nullptr);
http_task->start();
基本原理
UpstreamManager::upstream_create_weighted_random(
"simple.name",
true);//一主一备这项设什么没区别
AddressParams address_params = ADDRESS_PARAMS_DEFAULT;
address_params.server_type = 0;
UpstreamManager::upstream_add_server("simple.name", "main01.test.ted.bj.sogou", &address_params);//主
address_params.server_type = 1;
UpstreamManager::upstream_add_server("simple.name", "backup01.test.ted.gd.sogou", &address_params);//备
auto *http_task = WFTaskFactory::create_http_task("http://simple.name/request", 0, 0, nullptr);
auto *redis_task = WFTaskFactory::create_redis_task("redis://simple.name/2", 0, nullptr);
redis_task->get_req()->set_query("MGET", {"key1", "key2", "key3", "key4"});
(*http_task * redis_task).start();
基本原理
UpstreamManager::upstream_create_consistent_hash(
"abc.local",
nullptr);//nullptr代表使用框架默认的一致性哈希函数
AddressParams address_params = ADDRESS_PARAMS_DEFAULT;
address_params.server_type = 0;
address_params.group_id = 1001;
UpstreamManager::upstream_add_server("abc.local", "192.168.2.100:8081", &address_params);//main in group 1001
address_params.server_type = 1;
address_params.group_id = 1001;
UpstreamManager::upstream_add_server("abc.local", "192.168.2.100:8082", &address_params);//backup for group 1001
address_params.server_type = 0;
address_params.group_id = 1002;
UpstreamManager::upstream_add_server("abc.local", "main01.test.ted.bj.sogou", &address_params);//main in group 1002
address_params.server_type = 1;
address_params.group_id = 1002;
UpstreamManager::upstream_add_server("abc.local", "backup01.test.ted.gd.sogou", &address_params);//backup for group 1002
address_params.server_type = 1;
address_params.group_id = -1;
UpstreamManager::upstream_add_server("abc.local", "test.sogou.com:8080", &address_params);//backup for no group mean backup for all group and no group
UpstreamManager::upstream_add_server("abc.local", "abc.sogou.com");//main, no group
auto *http_task = WFTaskFactory::create_http_task("http://abc.local/service/method", 0, 0, nullptr);
http_task->start();
基本原理
UpstreamManager::upstream_create_vnswrr("nvswrr.random");
AddressParams address_params = ADDRESS_PARAMS_DEFAULT;
address_params.weight = 3;//权重为3
UpstreamManager::upstream_add_server("nvswrr.random", "192.168.2.100:8081", &address_params);//权重3
address_params.weight = 2;//权重为2
UpstreamManager::upstream_add_server("nvswrr.random", "192.168.2.100:8082", &address_params);//权重2
UpstreamManager::upstream_add_server("nvswrr.random", "abc.sogou.com");//权重1
auto *http_task = WFTaskFactory::create_http_task("http://nvswrr.random:9090", 0, 0, nullptr);
http_task->start();
基本原理
当发起请求的url的URIHost填UpstreamName时,视做对与名字对应的Upstream发起请求,接下来将会在Upstream记录的这组Address中进行选择:
round-robin/weighted-round-robin:视为与[1]等价,暂不提供
框架建议普通用户使用策略[2],可以保证集群具有良好的容错性和可扩展性
对于复杂需求场景,高级用户可以使用策略[3],订制复杂的选择逻辑
struct EndpointParams
{
size_t max_connections;
int connect_timeout;
int response_timeout;
int ssl_connect_timeout;
bool use_tls_sni;
};
static constexpr struct EndpointParams ENDPOINT_PARAMS_DEFAULT =
{
.max_connections = 200,
.connect_timeout = 10 * 1000,
.response_timeout = 10 * 1000,
.ssl_connect_timeout = 10 * 1000,
.use_tls_sni = false,
};
struct AddressParams
{
struct EndpointParams endpoint_params;
unsigned int dns_ttl_default;
unsigned int dns_ttl_min;
unsigned int max_fails;
unsigned short weight;
int server_type;
int group_id;
};
static constexpr struct AddressParams ADDRESS_PARAMS_DEFAULT =
{
.endpoint_params = ENDPOINT_PARAMS_DEFAULT,
.dns_ttl_default = 12 * 3600,
.dns_ttl_min = 180,
.max_fails = 200,
.weight = 1, //only for main of UPSTREAM_WEIGHTED_RANDOM
.server_type = 0,
.group_id = -1,
};
每个Addreess都可以配置自己的自定义参数:
平均修复时间(Mean time to repair,MTTR),是描述产品由故障状态转为工作状态时修理时间的平均值。
服务雪崩效应是一种因“服务提供者的故障”(原因),导致“服务调用者故障”(结果),并将不可用逐渐/逐级放大的现象
若不加以有效控制,效应不会收敛,而且会以几何级放大,犹如雪崩,雪崩效应因此得名
日常表现通常为:起初只是一个很小的服务or模块异常/超时,引起下游其他依赖的服务随之异常/超时,产生连锁反应,最终导致绝大多数甚至全部的服务陷入瘫痪
随着故障的修复,效应随之消失,所以效应持续时间通常等于MTTR
当某一个目标的错误or异常触达到预先设定的阈值条件时,暂时认为这个目标不可用,剔除目标,即熔断开启进入熔断期
在熔断持续时间达到MTTR时长后,会进入半熔断状态,(尝试)恢复目标
如果恢复的时候发现其他所有目标都被熔断,会同一时间把所有目标恢复
熔断机制策略可以有效阻止雪崩效应
MTTR=30秒,暂时不可配置,后续会考虑开放给用户自行配置
当某一个Addrees连续失败次数达到设定上限(默认200次),这个Address会被熔断MTTR=30秒
Address在熔断期间,一旦被策略选中,Upstream会根据具体配置决定是否尝试其他Address、如何尝试
请注意满足下面1-4的某个情景,通信任务将得到一个WFT_ERR_UPSTREAM_UNAVAILABLE = 1004的错误:
配置 UpstreamManager::upstream_add_server("my_proxy.name", "192.168.2.100:8081");
请求 http://my_proxy.name:456/test.html => http://192.168.2.100:8081/test.html
请求 http://my_proxy.name/test.html => http://192.168.2.100:8081/test.html
配置 UpstreamManager::upstream_add_server("my_proxy.name", "192.168.10.10");
请求 http://my_proxy.name:456/test.html => http://192.168.10.10:456/test.html
请求 http://my_proxy.name/test.html => http://192.168.10.10:80/test.html
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。