当前位置: 首页 > news >正文

网站换代理百度广告推广电话

网站换代理,百度广告推广电话,开发网站的流程步骤,北京改网站目录 1. 引言2. 启用vnswrr负载均衡模块3. 源码剖析3.1 配置指令分析3.2 负载均衡算法配置初始化3.3 负载均衡请求上下文的初始化3.4 获取peer 1. 引言 之前有讨论了nginx的swrr算法的两个问题#xff0c;并引出了阿里tengine的vnswrr算法如何来克服swrr的问题。本文通过源码层… 目录 1. 引言2. 启用vnswrr负载均衡模块3. 源码剖析3.1 配置指令分析3.2 负载均衡算法配置初始化3.3 负载均衡请求上下文的初始化3.4 获取peer 1. 引言 之前有讨论了nginx的swrr算法的两个问题并引出了阿里tengine的vnswrr算法如何来克服swrr的问题。本文通过源码层面对ngx_http_upstream_vnswrr_module模块进行分析来深入理解vnswrr负载均衡算法。关于swrr算法的思考可以查看《nginx upstream server主动健康检测模块添加https检测功能》。关于vnswrr的算法原理可以参考《阿里七层流量入口负载均衡算法演变之路》。 2. 启用vnswrr负载均衡模块 配置指令的格式为 指令 vnswrr [max_initinit_vode_num] 默认值 - 上下文: upstream 其中init_vnode_num是初始化虚拟节点的数量具体可以参考《阿里七层流量入口负载均衡算法演变之路》中**接入层 VNSWRR 算法V2**部分的描述。 以5台rs服务器为例开启vnswrr距离如下 upstream {vnswrr 5;server 192.168.0.1 weight1;server 192.168.0.2 weight1;server 192.168.0.3 weight3;server 192.168.0.4 weight3;server 192.168.0.5 weight5;server 192.168.0.6 weight5; } 3. 源码剖析 3.1 配置指令分析 本模块定义了配置指令vnswrr代码如下 static ngx_command_t ngx_http_upstream_vnswrr_commands[] {{ ngx_string(vnswrr),NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,ngx_http_upstream_vnswrr,0,0,NULL },ngx_null_command };以上定义了指令分析回调函数ngx_http_upstream_vnswrr, 其源码如下 static char * ngx_http_upstream_vnswrr(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {ngx_http_upstream_srv_conf_t *uscf;ngx_http_upstream_vnswrr_srv_conf_t *uvnscf;ngx_str_t *value;ngx_int_t max_init;uscf ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);if (uscf-peer.init_upstream) {ngx_conf_log_error(NGX_LOG_WARN, cf, 0,load balancing method redefined);}/* 将vnswrr的负载均衡算法配置初始化回调函数挂进去 */uscf-peer.init_upstream ngx_http_upstream_init_vnswrr;/* 不象哈希负载均衡算法本算法可以支持主备服务器 */uscf-flags NGX_HTTP_UPSTREAM_CREATE|NGX_HTTP_UPSTREAM_WEIGHT|NGX_HTTP_UPSTREAM_BACKUP|NGX_HTTP_UPSTREAM_MAX_FAILS|NGX_HTTP_UPSTREAM_FAIL_TIMEOUT #if defined(nginx_version) nginx_version 1011005|NGX_HTTP_UPSTREAM_MAX_CONNS #endif|NGX_HTTP_UPSTREAM_DOWN;/* 获取vnswrr的配置上下文 */uvnscf ngx_http_conf_upstream_srv_conf(uscf,ngx_http_upstream_vnswrr_module);value cf-args-elts;max_init 0;/* 如果有max_init参数就从配置指令中解析初始虚拟节点数量 */if (cf-args-nelts 1) {if (ngx_strncmp(value[1].data, max_init, 9) 0) {max_init ngx_atoi(value[1].data[9], value[1].len - 9);if (max_init NGX_ERROR) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,invalid parameter \%V\, value[1]);return NGX_CONF_ERROR;}}}uvnscf-max_init max_init;return NGX_CONF_OK; }3.2 负载均衡算法配置初始化 nginx在解析完配置文件后会为每个upstream调用前面设置好的init_upstream回调函数来初始化设置好的负载均衡算法对于开启了vnswrr算法则会回调ngx_http_upstream_init_vnswrr函数该回调由3.1节中ngx_http_upstream_vnswrr函数设置。下面来分析一下ngx_http_upstream_init_vnswrr函数 static ngx_int_t ngx_http_upstream_init_vnswrr(ngx_conf_t *cf,ngx_http_upstream_srv_conf_t *us) {ngx_http_upstream_rr_peers_t *peers, *backup;ngx_http_upstream_vnswrr_srv_conf_t *uvnscf, *ubvnscf;ngx_http_upstream_server_t *server;ngx_uint_t i, g, bg, max_init;ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf-log, 0, init vnswrr);/* 借用round-robin的ngx_http_upstream_init_round_robin初始化peer链表 */if (ngx_http_upstream_init_round_robin(cf, us) ! NGX_OK) {return NGX_ERROR;}/* 对于配置的每个server(包括主和备)计算配置的所有server权重的最大公约数 */g 0;bg 0;if (us-servers) {server us-servers-elts;for (i 0; i us-servers-nelts; i) {if (server[i].backup) {bg ngx_http_upstream_gcd(bg, server[i].weight);} else {g ngx_http_upstream_gcd(g , server[i].weight);}}}if (g 0) {g 1;}if (bg 0) {bg 1;}uvnscf ngx_http_conf_upstream_srv_conf(us,ngx_http_upstream_vnswrr_module);if (uvnscf NULL) {return NGX_ERROR;}peers (ngx_http_upstream_rr_peers_t *) us-peer.data;max_init uvnscf-max_init;/* init_number为初始虚拟节点的序号last_number为最后一次分配的虚拟节点的序号last_peer为最后一次分配的peer的指针*/uvnscf-init_number NGX_CONF_UNSET_UINT;uvnscf-last_number NGX_CONF_UNSET_UINT;uvnscf-last_peer NULL;uvnscf-next NULL;uvnscf-gcd g;/* 如果没有配置max_init则设置为peer的数量max_init最大为总的权重*/if (!max_init) {uvnscf-max_init peers-number;} else if (max_init peers-total_weight) {uvnscf-max_init peers-total_weight;}/* 设置负载均衡请求上下文初始化回调函数 */us-peer.init ngx_http_upstream_init_vnswrr_peer;/* 如果upstream是配置成带权重模式的即所有服务器的weight不都等于1则走正常vnswrr算法否则退化为简单的round-robin算法。对于vnswrr需要分配虚拟节点并进行初始化虚拟节点的数量是总权重除以上面算出的最大公约数。稍微思考一下就知道这个是合理的譬如三台server他们的权重都分别是2,4,6,那么其效果和1,2,3是一样的所以找到最大公约数并把这个最大公约数除掉以后得到有效权重。*/if (peers-weighted) {uvnscf-vpeers ngx_pcalloc(cf-pool,sizeof(ngx_http_upstream_rr_vpeers_t)* peers-total_weight / uvnscf-gcd);if (uvnscf-vpeers NULL) {return NGX_ERROR;}/* 初始化一批虚拟节点最多是max_init个虚拟节点避免一次性初始化大量的虚拟节点当值nginx的cpu突发overload*/ngx_http_upstream_init_virtual_peers(peers, uvnscf, 0, uvnscf-max_init);}/* 下面是backup服务器部分的初始化逻辑和主服务器是一样的 */backup peers-next;if (backup) {ubvnscf ngx_pcalloc(cf-pool,sizeof(ngx_http_upstream_vnswrr_srv_conf_t));if (ubvnscf NULL) {return NGX_ERROR;}ubvnscf-init_number NGX_CONF_UNSET_UINT;ubvnscf-last_number NGX_CONF_UNSET_UINT;ubvnscf-last_peer NULL;ubvnscf-gcd bg;ubvnscf-max_init max_init;if (!max_init) {ubvnscf-max_init backup-number;} else if (max_init backup-total_weight) {ubvnscf-max_init backup-total_weight;}/* 把主服务器和backup服务器链起来 */uvnscf-next ubvnscf;if (!backup-weighted) {return NGX_OK;}ubvnscf-vpeers ngx_pcalloc(cf-pool,sizeof(ngx_http_upstream_rr_vpeers_t)* backup-total_weight / ubvnscf-gcd);if (ubvnscf-vpeers NULL) {return NGX_ERROR;}ngx_http_upstream_init_virtual_peers(backup, ubvnscf, 0, ubvnscf-max_init);}return NGX_OK; }ngx_http_upstream_init_vnswrr函数的逻辑就是分别对主服务器和备服务器组进行加载操作初始化一部分虚拟节点详细的逻辑在源码中已经进行了注释不再赘述。 3.3 负载均衡请求上下文的初始化 当nginx接收到http请求需要连接上游服务器的时候就会发起负载均衡请求上下文的初始化回调对于vnswrr算法就是回调ngx_http_upstream_init_vnswrr_peer函数了。 static ngx_int_t ngx_http_upstream_init_vnswrr_peer(ngx_http_request_t *r,ngx_http_upstream_srv_conf_t *us) {ngx_http_upstream_vnswrr_srv_conf_t *uvnscf;ngx_http_upstream_vnswrr_peer_data_t *vnsp;uvnscf ngx_http_conf_upstream_srv_conf(us,ngx_http_upstream_vnswrr_module);/* 创建请求上下文并进行初始化设置 */vnsp ngx_palloc(r-pool, sizeof(ngx_http_upstream_vnswrr_peer_data_t));if (vnsp NULL) {return NGX_ERROR;}vnsp-uvnscf uvnscf;r-upstream-peer.data vnsp-rrp;/* 因为本模块是依赖于round-robin模块的譬如上游服务器的已分配状态等这里也需要调用ngx_http_upstream_init_round_robin_peer进行初始化 */if (ngx_http_upstream_init_round_robin_peer(r, us) ! NGX_OK) {return NGX_ERROR;}/* 设置获取peer的回调 */r-upstream-peer.get ngx_http_upstream_get_vnswrr_peer;return NGX_OK; }这里最关键的就是设置了获取peer的回调函数ngx_http_upstream_get_vnswrr_peer。 3.4 获取peer 一切准备就绪后nginx会在请求上游连接的时候调用ngx_event_connect_peer而在ngx_event_connect_peer函数中将回调ngx_http_upstream_get_vnswrr_peer函数来获取目的服务器的地址信息。接下来来详细分析这个函数源码如下 static ngx_int_t ngx_http_upstream_get_vnswrr_peer(ngx_peer_connection_t *pc, void *data) {ngx_http_upstream_vnswrr_peer_data_t *vnsp data;ngx_int_t rc;ngx_uint_t i, n;ngx_http_upstream_rr_peer_t *peer;ngx_http_upstream_rr_peers_t *peers;ngx_http_upstream_rr_peer_data_t *rrp;ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc-log, 0,get vnswrr peer, try: %ui, pc-tries);pc-cached 0;pc-connection NULL;rrp vnsp-rrp;peers rrp-peers;ngx_http_upstream_rr_peers_wlock(peers); /* 共享内存加写锁 */if (peers-single) {/*对于只有一个peer的情况如果这个peer没有down且连接数没有超过限制则直接分配这个peer*/peer peers-peer;if (peer-down) {goto failed;}#if defined(nginx_version) nginx_version 1011005if (peer-max_conns peer-conns peer-max_conns) {goto failed;} #endif#if (NGX_HTTP_UPSTREAM_CHECK)if (ngx_http_upstream_check_peer_down(peer-check_index)) {goto failed;} #endifrrp-current peer;} else {/* 如果有多个peer,则调用ngx_http_upstream_get_vnswrr获取peer信息 */peer ngx_http_upstream_get_vnswrr(vnsp);if (peer NULL) {goto failed;}ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc-log, 0,get vnswrr peer, current: %p %i,peer, peer-current_weight);}/* 将分配到的peer的地址写入到ngx_peer_connection_t(pc_中 */pc-sockaddr peer-sockaddr;pc-socklen peer-socklen;pc-name peer-name; #if (T_NGX_HTTP_DYNAMIC_RESOLVE)pc-host peer-host; #endif peer-conns;/* 释放上面加的写锁 */ngx_http_upstream_rr_peers_unlock(peers);return NGX_OK;failed:/* 主服务器分配失败了如果有备服务器那么从备服务器进行分配 */if (peers-next) {ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc-log, 0, backup servers);/* 切换到备服务器组 */rrp-peers peers-next;vnsp-uvnscf vnsp-uvnscf ? vnsp-uvnscf-next : vnsp-uvnscf;n (rrp-peers-number (8 * sizeof(uintptr_t) - 1))/ (8 * sizeof(uintptr_t));for (i 0; i n; i) {rrp-tried[i] 0;}/* 释放上面加的写锁 */ngx_http_upstream_rr_peers_unlock(peers);/* 递归调用本函数自己重新进行一次获取peer的操作 */rc ngx_http_upstream_get_vnswrr_peer(pc, vnsp);/* 备服务器也分配失败则返回NGX_BUSY */if (rc ! NGX_BUSY) {return rc;}/* 重新加上写锁在返回前释放 */ngx_http_upstream_rr_peers_wlock(peers);}/* 释放上面加的写锁 */ngx_http_upstream_rr_peers_unlock(peers);pc-name peers-name;return NGX_BUSY; }本函数针对如果只有一个peer的情况来说就不需要再进行vnswrr算法了反过来则进行vnswrr的分配操作vnswrr算法调用了ngx_http_upstream_get_vnswrr函数进行实际的分配工作。下面就是vnswrr的最核心的代码了源码如下 static ngx_http_upstream_rr_peer_t * ngx_http_upstream_get_vnswrr(ngx_http_upstream_vnswrr_peer_data_t *vnsp) {time_t now;uintptr_t m;ngx_uint_t i, n, p, flag, begin_number;ngx_http_upstream_rr_peer_t *peer, *best;ngx_http_upstream_rr_peers_t *peers;ngx_http_upstream_rr_vpeers_t *vpeers;ngx_http_upstream_rr_peer_data_t *rrp;ngx_http_upstream_vnswrr_srv_conf_t *uvnscf;now ngx_time();best NULL;#if (NGX_SUPPRESS_WARN)p 0; #endifrrp vnsp-rrp;peers rrp-peers;uvnscf vnsp-uvnscf;vpeers uvnscf-vpeers;/* last_number NGX_CONF_UNSET_UINT表示本worker进程第一次进入到ngx_http_upstream_get_vnswrr函数这里通过将init_number设置为一个随机值来避免多进程产生的“共振”效应。初始化随机值这个机制在《阿里七层流量入口负载均衡算法演变之路》中有提到*/if (uvnscf-last_number NGX_CONF_UNSET_UINT) {uvnscf-init_number ngx_random() % peers-number;/* 如果是带权重模式则使用了虚拟节点来进行负载均衡所以从虚拟节点中选取peer*/if (peers-weighted) {peer vpeers[uvnscf-init_number].vpeer;} else {/* 如果是不带权重的模式则没有虚拟节点需要直接在peers列表中循环init_number次数选择第nit_number个peer*/for (peer peers-peer, i 0; i uvnscf-init_number; i) {peer peer-next;}}uvnscf-last_number uvnscf-init_number;uvnscf-last_peer peer;}if (peers-weighted) {/* 如果当前初始化好的虚拟节点已经都被分配过一次了并且还有没初始化过的虚拟节点则再次分配虚拟节点最多max_init个。 */if (uvnscf-vnumber ! peers-total_weight / uvnscf-gcd (uvnscf-last_number 1 uvnscf-vnumber)){n peers-total_weight / uvnscf-gcd - uvnscf-vnumber;if (n uvnscf-max_init) {n uvnscf-max_init;}ngx_http_upstream_init_virtual_peers(peers, uvnscf, uvnscf-vnumber,n uvnscf-vnumber);}/* 在虚拟节点循环队列中分配下一个vpeerbegin_numer为当前分配的虚拟节点在虚拟节点循环队列中的序号*/ begin_number (uvnscf-last_number 1) % uvnscf-vnumber;peer vpeers[begin_number].vpeer;} else {/* 如果是不带权重模式那么直接通过peer链进行peer的分配一个peer中有多个地址的那么先分配这个peer的地址否则找下一个peerbegin_number为当前分配的peer在peer列表中的序号*/if (uvnscf-last_peer uvnscf-last_peer-next) {begin_number (uvnscf-last_number 1) % peers-number;peer uvnscf-last_peer-next;} else {begin_number 0;peer peers-peer;}}/* 以下对上面分配的peer进行状态过滤如果分配的peer不能用需要再往下循环获取下一个peer *//* 这里 i ! begin_number || flag的判断用来检测是否已经循环了一圈回来了循环了一圈回来的那么所有的peer就已经遍历了还是不能满足分配的需要。*/for (i begin_number, flag 1; i ! begin_number || flag;i peers-weighted? ((i 1) % uvnscf-vnumber) : ((i 1) % peers-number),peer peers-weighted? vpeers[i].vpeer : (peer-next ? peer-next : peers-peer)){flag 0;if (peers-weighted) {/* 这里也有可能分配的虚拟节点已经被遍历过一次了并且还有没初始化过的虚拟节点则再次分配虚拟节点最多max_init个 */n peers-total_weight / uvnscf-gcd - uvnscf-vnumber;if (n uvnscf-max_init) {n uvnscf-max_init;}if (n 0) {ngx_http_upstream_init_virtual_peers(peers, uvnscf, uvnscf-vnumber,n uvnscf-vnumber);}n vpeers[i].rindex / (8 * sizeof(uintptr_t));m (uintptr_t) 1 vpeers[i].rindex % (8 * sizeof(uintptr_t));} else {n i / (8 * sizeof(uintptr_t));m (uintptr_t) 1 i % (8 * sizeof(uintptr_t));}/* 节点是否已经分配过的状态判断 */if (rrp-tried[n] m) {continue;}/* 节点是否已经被设置为down状态判断 */if (peer-down) {continue;}/* 节点是否故障保护状态判断 */if (peer-max_fails peer-fails peer-max_fails now - peer-checked peer-fail_timeout){continue;}/* 节点的当前在线连接是否超过限制判断 */ #if defined(nginx_version) nginx_version 1011005if (peer-max_conns peer-conns peer-max_conns) {continue;} #endif#if (NGX_HTTP_UPSTREAM_CHECK)if (ngx_http_upstream_check_peer_down(peer-check_index)) {continue;} #endif/* 得到了分配好的节点 */best peer;uvnscf-last_peer peer;uvnscf-last_number i;p i;break;}if (best NULL) {return NULL;}rrp-current best;/* 在tried位表中设置当前节点已经被分配过 */if (peers-weighted) {n vpeers[p].rindex / (8 * sizeof(uintptr_t));m (uintptr_t) 1 vpeers[p].rindex % (8 * sizeof(uintptr_t));} else {n p / (8 * sizeof(uintptr_t));m (uintptr_t) 1 p % (8 * sizeof(uintptr_t));}rrp-tried[n] | m;if (now - best-checked best-fail_timeout) {best-checked now;}return best; }以上函数中如果是不带权重的模式那么就是最简单的round-robin分配机制每次分配就循环往后前进一个peer一个特别的地方就是第一次分配的时候设置了一个随机值位置从这个随机位置开始进行正式分配避免产生“共振”如果是带权重的模式那么才是真正的vnswrr算法这个算法另外创建了虚拟节点虚拟节点的总数量是总权重/各服务器权重的最大公约数为了避免一次性集中分配虚拟节点导致CPU压力突发所以每次最多分配max_init个数的虚拟节点。   这是这些逻辑交织在一起看上去ngx_http_upstream_get_vnswrr函数似乎有些复杂了。   和不带权重的模式一样它也会在第一次分配的时候设置一个随机值位置从随机的虚拟节点开始分配避免“共振”现象的发生。 除了以上特别说明的部分其他逻辑几乎就是round-robin代码的翻版还是非常好理解的本文列出的源码中也给出了注释就不再赘述了。
http://www.zqtcl.cn/news/970102/

相关文章:

  • 3d建模在线制作网站阿里云域名注册官网
  • 创建网站大约多少钱网站建设排序题
  • 大庆做网站找谁机构编制网站建设
  • 网站标题特效网站弹出的对话框怎么做
  • 找深圳网站建设wordpress 页面背景
  • 企业网站怎么维护上海注册建网站
  • 四川省建设工程造价信息网站便宜做网站价格
  • 医院网站优化策划网站开发的项目需求
  • 网站优化公司服务直播软件怎么开发
  • 网站建设 有道翻译织梦修改网站后备份
  • 苏州网联盛网站建设做最好的在线看片网站
  • 一个空间怎么放2个网站陕西城乡住房建设部网站
  • 如何购买虚拟主机做网站企业查名
  • 动易网站默认密码网站怎么做 吸引人
  • 站长工具国产2023二级建造师证书查询官方网站
  • 微信小程序联盟网站北京网站建设华大
  • 人事怎么做招聘网站比对分析crm管理系统 一般包含
  • 林业网站建设有哪些北京微信小程序开发
  • ppt素材网站建设流程图网站开发原型工具
  • 乡镇医院网站建设成都市企业网站建设
  • 网站编辑如何做原创网站中英切换实例
  • 哈尔滨道外区建设局官方网站wordpress简称
  • 教师网站建设企业实践总结华为应用商店下载安装
  • 常见的网站空间服务商资阳建设局网站
  • 惠通网站建设湖南seo优化服务
  • 网站建设价格标准wordpress花钱吗
  • 龙门惠州网站建设苏州公司注册查询
  • 城阳网站设计自建网站与平台建站
  • 网站建设文字教程wordpress xml生成
  • wordpress修改注册表广西seo网站