nginx的ip_hash算法

这篇具有很好参考价值的文章主要介绍了nginx的ip_hash算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概念

根据用户请求的ip,利用算法映射成hash值,分配到特定的tomcat服务器中。主要是为了实现负载均衡,只要用户ip固定,则hash值固定,特定用户只能访问特定服务器,解决了session的问题。

源码分析

ip_hash算法的处理代码位于src\http\modules\ngx_http_upstream_ip_hash_module.c。主要的处理代码如下:

// 最大失败次数、超时时间、最大连接数等相关配置
#define NGX_HTTP_UPSTREAM_CREATE        0x0001
#define NGX_HTTP_UPSTREAM_WEIGHT        0x0002
#define NGX_HTTP_UPSTREAM_MAX_FAILS     0x0004
#define NGX_HTTP_UPSTREAM_FAIL_TIMEOUT  0x0008
#define NGX_HTTP_UPSTREAM_DOWN          0x0010
#define NGX_HTTP_UPSTREAM_BACKUP        0x0020
#define NGX_HTTP_UPSTREAM_MAX_CONNS     0x0100

static ngx_int_t
ngx_http_upstream_get_ip_hash_peer(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 */

    ngx_http_upstream_rr_peers_rlock(iphp->rrp.peers);

    if (iphp->tries > 20 || iphp->rrp.peers->single) {
        ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers);
        return iphp->get_rr_peer(pc, &iphp->rrp);
    }

    now = ngx_time();

    pc->cached = 0;
    pc->connection = NULL;

    // 原始哈希值
    hash = iphp->hash;

    for ( ;; ) {

        // 计算ip hash
        for (i = 0; i < (ngx_uint_t) iphp->addrlen; i++) {
            hash = (hash * 113 + iphp->addr[i]) % 6271;
        }

        // 根据hash和权重找到对应服务器
        w = hash % iphp->rrp.peers->total_weight;
        peer = iphp->rrp.peers->peer;
        p = 0;

        while (w >= peer->weight) {
            w -= peer->weight;
            peer = peer->next;
            p++;
        }

        n = p / (8 * sizeof(uintptr_t));
        m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));

        if (iphp->rrp.tried[n] & m) {
            goto next;
        }

        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                       "get ip hash peer, hash: %ui %04XL", p, (uint64_t) m);

        ngx_http_upstream_rr_peer_lock(iphp->rrp.peers, peer);

        // 如果服务器不可用,不做后续处理
        if (peer->down) {
            ngx_http_upstream_rr_peer_unlock(iphp->rrp.peers, peer);
            goto next;
        }

        // 如果超过最大失败次数或者超时,不做后续处理
        if (peer->max_fails
            && peer->fails >= peer->max_fails
            && now - peer->checked <= peer->fail_timeout)
        {
            ngx_http_upstream_rr_peer_unlock(iphp->rrp.peers, peer);
            goto next;
        }

        // 如果超过最大连接数,不做后续处理
        if (peer->max_conns && peer->conns >= peer->max_conns) {
            ngx_http_upstream_rr_peer_unlock(iphp->rrp.peers, peer);
            goto next;
        }

        break;

    next:

        if (++iphp->tries > 20) {
            ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers);
            return iphp->get_rr_peer(pc, &iphp->rrp);
        }
    }

    iphp->rrp.current = peer;

    pc->sockaddr = peer->sockaddr;
    pc->socklen = peer->socklen;
    pc->name = &peer->name;

    // 连接数自增
    peer->conns++;

    if (now - peer->checked > peer->fail_timeout) {
        peer->checked = now;
    }

    ngx_http_upstream_rr_peer_unlock(iphp->rrp.peers, peer);
    ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers);

    iphp->rrp.tried[n] |= m;
    iphp->hash = hash;

    return NGX_OK;
}

算法的核心处理代码如下:

for (i = 0; i < (ngx_uint_t) iphp->addrlen; i++) {
    hash = (hash * 113 + iphp->addr[i]) % 6271;
}

通过查看源码得知,ipv4的情况下iphp->addrlen的值固定为3,源代码如下:

switch (r->connection->sockaddr->sa_family) {

    case AF_INET:   // ipv4
        sin = (struct sockaddr_in *) r->connection->sockaddr;
        iphp->addr = (u_char *) &sin->sin_addr.s_addr;
        iphp->addrlen = 3;  
        break;

#if (NGX_HAVE_INET6)
    case AF_INET6:  // ipv6
        sin6 = (struct sockaddr_in6 *) 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_addr;
        iphp->addrlen = 3;
    }

假如我们传递的ip为192.168.41.33,hash值得计算流程可以拆分为:

hash0 = iphp->hash;

# iphp->addr[0]--->192
hash1 = (hash0 * 113 + iphp->addr[0]) % 6271;

# iphp->addr[1]--->168
hash2 = (hash1 * 113 + iphp->addr[1]) % 6271;

# iphp->addr[2]--->41
hash3 = (hash2 * 113 + iphp->addr[2]) % 6271;

经分析得知,ip_hash实际是取ip地址得前三个字段计算得来,那么譬如192.168.41.xxx同一网段的ip访问的是同一个tomacat。

根据hash和权重找到对应的后端,源代码如下:

w = hash % iphp->rrp.peers->total_weight;
peer = iphp->rrp.peers->peer;
p = 0;

while (w >= peer->weight) {
    w -= peer->weight;
    peer = peer->next;
    p++;
}

// ...

需要注意的一点是,当一个正在以ip_hash方式管理的服务器在实际操作环境中被移除时,在nginx.conf中不能直接把对应的配置删除,在后面加down即可,因为删除后需要重新计算hash,处理这一过程会更加消耗资源。nginx.conf配置文件修改如下:

# 以ip_hash的方式实现负载均衡, 添加ip_hash即可
upstream dongserver {
    ip_hash;      
    server 192.168.41.33:8080;
    server 192.168.41.34:8081;
    server 192.168.41.35:8082 down;  # 服务器不可用
}

nginx源码中对此的处理如下:文章来源地址https://www.toymoban.com/news/detail-550859.html

# upstream块结构体
struct ngx_http_upstream_rr_peer_s {
    //...

    ngx_uint_t                      down;    // 服务器是否可用

    //...
};

# 当判断到down标志被竖起来之后,不做后续处理
if (peer->down) {
    ngx_http_upstream_rr_peer_unlock(iphp->rrp.peers, peer);
    goto next;
}

到了这里,关于nginx的ip_hash算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • nginx负载均衡简介,一般轮询、加权轮询、ip_hash等负载均衡模式配置介绍

    目录 一.负载均衡含义简介 二.nginx负载均衡配置方式 准备三台设备: 2.190均衡服务器,2.191web服务器1,2.160web服务器2,三台设备均安装nginx,两台web服务器均有网页内容 upstream内参数 1.一般轮询负载均衡 (1)含义 (2)配置 (3)测试 2.加权轮询负载均衡 (1)含义 (2)配置

    2024年02月10日
    浏览(48)
  • Nginx警告could not build optimal types_hash, you should increase either types_hash_max_size: 2048解决方案

    现象 今天在服务器上新装了一个Nginx,做了相关配置之后,验证配置时,报警告如下: 为了方便阅读,给手动换行了。 我哪见过这种场面呀,不过试了一下,虽然出现警告,但是Nginx启动没有问题。 但这个警告真的是碍眼,还是要解决掉。 解决方法 编辑Nginx配置文件, /e

    2024年02月14日
    浏览(51)
  • 详解一致性hash算法(Consistent-hashing):原理、图解、代码示例

    Consistent hashing is a scheme that provides hash table functionality in a way that the addition or removal of one slot does not significantly change the mapping of keys to slots. Hash算法是一种将任意长度的消息压缩到一个固定长度的输出(即哈希值)的算法。它主要用于数据完整性校验、数据加密、数字签名等方面

    2024年02月07日
    浏览(46)
  • Vue学习笔记 之 History 路由 和 Hash 路由的区别 及 History 模式时,Nginx的配置方式

    一、History 模式、Hash 模式   Vue Router 是 Vue.js 官方的路由管理器,用于构建单页应用的前端路由。它允许你通过定义路由配置来映射不同的 URL 到对应的组件,实现页面间的跳转和导航。Vue Router 支持两种路由模式:history 模式和 hash 模式。 1、History 模式   在 History 模式

    2024年02月07日
    浏览(37)
  • 【算法】【算法杂谈】具有setall功能的hash表

    当前所有算法都使用测试用例运行过,但是不保证100%的测试用例,如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识! 原问题 纳管一个hashmap,增强hashmap的功能,使其具有能够立刻将当前hash表中的所有值都变成统一的值的能力 具体来讲,就是如

    2024年02月02日
    浏览(42)
  • 哈希算法(hash)加密解密

    套路一样 hash_jiemi.py

    2024年02月13日
    浏览(44)
  • Hash(哈希)算法-Python实现

    哈希算法将任意长度的二进制值映射为较短的固定长度的二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希都将产生不同的值。要找到散列为同一个值的两个不同的

    2023年04月15日
    浏览(36)
  • 关于Secure Hash Algorithm加密算法

    一、概述 SHA(Secure Hash Algorithm)加密算法是一种广泛应用的密码散列函数,由美国国家安全局(NSA)设计,用于保障数据的安全性和完整性。SHA算法经历了多个版本的更新,目前主要应用于各种网络安全和数据加密领域。 SHA在线加密 | 一个覆盖广泛主题工具的高效在线平台

    2024年02月04日
    浏览(43)
  • Hash算法的特点、应用和实现方法详解

    什么是Hash算法?Hash算法,简称散列算法,也成哈希算法(英译),是将一个大文件映射成一个小串字符。与指纹一样,就是以较短的信息来保证文件的唯一性的标志,这种标志与文件的每一个字节都相关,而且难以找到逆向规律。 正向快速:给定明文和 hash 算法,在有限时

    2024年02月08日
    浏览(43)
  • 数据结构与算法 | 哈希表(Hash Table)

    在二分搜索中提到了在有序集合中查询某个特定元素的时候,通过折半的方式进行搜索是一种很高效的算法。那能否根据特征直接定位元素,而非折半去查找?哈希表(Hash Table),也称为散列表,就是一种数据结构,用于实现键-值对的映射关系。它通过将键映射到特定的值

    2024年02月06日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包