We have previously introduced the Weighted Round Robin (http://blog.csdn.net/xiajun07061225/article/details/9318871) strategy of nginx load balancing, which is the basic policy of nginx load balancing, so some initialization work, such as configuration value dump, other policies can be reused directly. You can see in the subsequent initialization code.
Note: The source code version in this article is Nginx-1.4.0.
IP hash initialize the IP hash initialization function ngx_http_upstream_init_ip_hash (ngx_http_upstream_ip_hash_module.c ):
Static round (ngx_conf_t * Cf, ngx_http_upstream_srv_conf_t * US) {// call the Weighted Round Robin if (ngx_http_upstream_init_round_robin (CF, US )! = Ngx_ OK) {return ngx_error;} // modified the callback function US-> peer. init = ngx_http_upstream_init_ip_hash_peer; return ngx_ OK;} for initialization of a single request ;}
Select the backend server. When the client requests, the initialization function ngx_http_upstream_init_ip_hash_peer is executed. The initialization function in the polling algorithm is called. Source code:
Static topology (ngx_http_request_t * r, ngx_http_upstream_srv_conf_t * US) {struct sockaddr_in * sin; // support for IPv6 # If (ngx_have_inet6) struct sockaddr_in6 * sin6; # endif ngx_http_upstream_ip_hash_peer_data_t * iphp; iphp = ngx_palloc (R-> pool, sizeof (ngx_http_upstream_ip_hash_peer_data_t); If (iphp = NULL) {return ngx_error;} r-> upstream-> peer. data = & iphp-> RRP; // call The initialization function in the RR algorithm, if (ngx_http_upstream_init_round_robin_peer (R, US )! = Ngx_ OK) {return ngx_error;} // set the callback function. Select the callback function r-> upstream-> peer. get = ngx_http_upstream_get_ip_hash_peer; Switch (R-> connection-> sockaddr-> sa_family) {// Save the client address case af_inet: sin = (struct sockaddr_in *) r-> connection-> sockaddr; iphp-> ADDR = (u_char *) & sin-> sin_addr.s_addr; // The IPv4 dump takes only the first three bytes, in the subsequent hash calculation process, only three bytes of iphp-> addrlen = 3; break; # If (ngx_have_inet6) Case af_inet6: sin6 = (struct sockaddr_in6 *) are used *) r-> connection-> sockaddr; iphp-> ADDR = (u_char *) & sin6-> sin6_addr.s6_addr; iphp-> addrlen = 16; break; # endif default: iphp-> ADDR = ngx_http_upstream_ip_hash_pseudo do_addr; iphp-> addrlen = 3;} // initialize the hash seed iphp-> hash = 89; // Number of initialization failed attempts iphp-> tries = 0; // function for RR selection-> get_rr_peer = ngx_http_upstream_get_round_assist_peer; return ngx_ OK ;}
The structure ngx_http_upstream_ip_hash_peer_data_t:
Typedef struct {/* the round robin data must be first */ngx_http_upstream_rr_peer_data_t RRP; // hash seed value ngx_uint_t hash; // ip address u_char addrlen; u_char * ADDR; // number of attempts to connect u_char tries; ngx_event_get_peer_pt get_rr_peer;} bytes; typedef struct {// pointer to all servers * peers; // The current server ngx_uint_t current; // The pointer to the bitmap uintptr_t * tried; // The actual storage location of the bitmap uintptr _ T data;} identifier; typedef struct identifier; struct ngx_http_upstream_rr_peers_s {ngx_uint_t number; // total number of all server addresses/* ngx_mutex_t * mutex; */ngx_uint_t total_weight; // total weight of all services unsigned single: 1; // whether there is only one backend service unsigned weighted: 1; // number! = Total_weight? Ngx_str_t * Name; ngx_http_upstream_rr_peers_t * Next; ngx_http_upstream_rr_peer_t peer [1];};
The specific function is ngx_http_upstream_get_ip_hash_peer:
Static upload (ngx_peer_connection_t * PC, void * Data) {ngx_http_upstream_ip_hash_peer_data_t * iphp = data; time_t now; ngx_int_t W; uintptr_t m; ngx_uint_t I, N, P, hash; ngx_http_upstream_rr_peer_t * peer; ngx_log_debug1 (ngx_log_debug_http, PC-> log, 0, "Get IP hash peer, try: % UI", PC-> tries);/* todo: cached * // if there are too many failures or only one backend service, select if (iphp-> tries> 2 for RR. 0 | iphp-> RRP. peers-> single) {return iphp-> get_rr_peer (PC, & iphp-> RRP);} Now = ngx_time (); PC-> cached = 0; PC-> connection = NULL; hash = iphp-> hash; For (;) {// calculate the hash value of the IP address for (I = 0; I <iphp-> addrlen; I ++) {// 113 prime number, which allows hash results to be hashed = (hash * 113 + iphp-> ADDR [I]) % 6271 ;} // obtain the selected backend server if (! IPhone-> RRP. peers-> weighted) {P = hash % iphp-> RRP. peers-> Number;} else {W = hash % iphp-> RRP. peers-> total_weight; for (I = 0; I <iphp-> RRP. peers-> Number; I ++) {w-= iphp-> RRP. peers-> peer [I]. weight; If (W <0) {break ;}} P = I ;}// the server calculates n = P/(8 * sizeof (uintptr_t) in the bitmap position )); M = (uintptr_t) 1 <P % (8 * sizeof (uintptr_t); If (! (Iphp-> RRP. tried [N] & M) {ngx_log_debug2 (ngx_log_debug_http, PC-> log, 0, "Get IP hash peer, hash: % UI % 04xa", P, M ); // obtain the server peer = & iphp-> RRP. peers-> peer [p];/* ngx_lock_mutex (iphp-> RRP. peers-> mutex); * // If (! Peer-> down) {// the number of failures has reached the upper limit. If (peer-> max_fails = 0 | peer-> fails <peer-> max_fails) {break ;} if (now-peer-> checked> peer-> fail_timeout) {peer-> checked = now; break ;}// change the bitmap tag value iphp-> RRP. tried [N] | = m;/* ngx_unlock_mutex (iphp-> RRP. peers-> mutex); * // The number of attempts that can be made after the current connection fails when a remote server is connected. PC-> tries --;} // If (++ iphp-> tries >=20) {return iphp-> get_rr_peer (PC, & iphp-> RRP) ;}// the current service index iphp-> RRP. current = P; // Save the server address and name PC-> sockaddr = peer-> sockaddr; PC-> socklen = peer-> socklen; PC-> name = & peer-> name;/* ngx_unlock_mutex (iphp-> RRP. peers-> mutex); * // The bitmap updates the iphp-> RRP. tried [N] | = m; // preserve the seed so that the next time get_ip_hash_peer is used to select iphp-> hash = hash; return ngx_ OK ;}
During the above calculation, when ing Based on the IP hash value, the weighted field in the header structure of the server list is divided into two different cases. Let's take a look at the weighted computing process (ngx_http_upstream_round_assist.c ):
// Point to the server list pointer server = US-> servers-> ELTs; n = 0; W = 0; // traverse the server list, calculate the total number of addresses and the total weights for (I = 0; I <US-> servers-> nelts; I ++) {If (server [I]. backup) {continue;} n + = server [I]. naddrs; W + = server [I]. naddrs * server [I]. weight;} // weighted calculates peers-> weighted = (W! = N );
The server type is ngx_http_upstream_server_t.
Typedef struct {ngx_addr_t * addrs; // pointer to the array storing IP addresses, host information (corresponding to ngx_url_t-> addrs) ngx_uint_t naddrs; // used with the first parameter, number of array elements (corresponding to ngx_url_t-> naddrs) ngx_uint_t weight; // weight ngx_uint_t max_fails; time_t fail_timeout; unsigned down: 1; unsigned backup: 1;} success;
A domain name may correspond to multiple IP addresses. Server wegiht field, which is used as the server weight and corresponds to the number of virtual nodes. The specific algorithm virtualizes each server into N nodes and evenly distributes them to the hash ring. Each request calculates a hash value based on the configured parameters, search for the virtual node closest to the hash in the hash ring, and the corresponding server serves as the backend machine of the request. Therefore, when the weighted field is equal to 0, the number of virtual nodes and the number of IP addresses are equal. Therefore, you can directly modulo the hash value against the total number of IP addresses. If weighted is not equal to 0, the number of virtual nodes and the number of IP addresses are different. Therefore, the number of virtual nodes must be calculated separately. Find the virtual node closest to the hash and act as the backend machine of the request. The process of selecting IP hash is as follows:
Compared with the Weighted Round Robin (WRR), the round robin (WRR) and IP hashing (WRR) policies have higher applicability, independent of any client information, and completely dependent on backend servers. Client requests can be distributed to backend servers more reasonably and evenly. Disadvantages: multiple requests from the same client may be distributed to different backend servers for processing, which cannot meet the needs of applications for session persistence. Advantages of the IP hash policy: it can allocate multiple requests from the same client to the same server for processing, avoiding the need that Weighted Round Robin cannot be applied to session persistence. Disadvantage: when there are a lot of requests from a certain IP address at a certain time point, the pressure on a backend server may be very high, while other backend servers are idle and unbalanced. For more information, see: http://blog.dccmx.com/2011/07/nginx-upstream-src-1/http://itoedr.blog.163.com/blog/static/120284297201341044034750/
In-depth analysis of nginx, in-depth understanding of nginx-module development and Architecture Analysis