Transferred from: Smoke and rain in the south of the Yangtze River
IP hash Initialization
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 backend server
After the client requests, the initialization function ngx_http_upstream_init_ip_hash_peer will be executed. The initialization function in the polling algorithm is called.
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 ;}
The flowchart 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,