美文网首页
记一个Nginx线上问题

记一个Nginx线上问题

作者: 诺之林 | 来源:发表于2020-07-20 22:00 被阅读0次

    目录

    问题

    • 通过监控ELK日志 线上出现如下错误
    414 Request-URI Too Large
    
    • 怀疑是GET参数太大导致URL过长
    image.png
    • 于是尝试在本地环境复现上述问题

    复现

    Java

    sudo apt install -y openjdk-8-jdk
    
    curl -s get.sdkman.io | bash
    
    source "$HOME/.sdkman/bin/sdkman-init.sh"
    
    sdk install springboot 2.1.13.RELEASE
    
    spring init -b 2.1.13.RELEASE -dweb --build gradle HelloSpring && cd HelloSpring
    
    ./gradlew bootrun
    
    curl localhost:8080
    # {"timestamp":"2020-07-28T11:22:33.995+0000","status":404,"error":"Not Found","message":"No message available","path":"/"}
    

    Nginx

    sudo apt install -y nginx
    
    sudo vim /etc/nginx/sites-enabled/java.conf
    
    server {
        listen 80;
        server_name 192.168.56.150.xip.io;
    
        location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://127.0.0.1:8080;
            proxy_read_timeout 90;
        }
    }
    
    sudo nginx -t
    
    sudo nginx -s reload
    
    • 测试脚本
    vim request.sh
    
    #!/bin/bash
    
    url="http://192.168.56.150.xip.io?ids=1"
    
    for i in {1000..3000}
    do
        url="${url},$i"
    done
    
    echo ${url}
    curl ${url}
    
    bash request.sh
    
    <html>
    
    <head>
        <title>414 Request-URI Too Large</title>
    </head>
    
    <body bgcolor="white">
        <center>
            <h1>414 Request-URI Too Large</h1>
        </center>
        <hr>
        <center>nginx/1.10.3 (Ubuntu)</center>
    </body>
    
    </html>
    

    解决

    Nginx

    sudo vim /etc/nginx/nginx.conf
    # large_client_header_buffers 4 512k;
    
    sudo nginx -t
    
    sudo nginx -s reload
    
    bash request.sh
    # java.lang.IllegalArgumentException: Request header is too large
    
    <!doctype html>
    <html lang="en">
    
    <head>
        <title>HTTP Status 400 – Bad Request</title>
    </head>
    
    <body>
        <h1>HTTP Status 400 – Bad Request</h1>
    </body>
    
    </html>
    

    Java

    vim src/main/resources/application.properties
    
    server.max-http-header-size=500000
    
    ./gradlew bootrun
    
    bash request.sh
    # {"timestamp":"2020-07-28T11:22:33.692+0000","status":404,"error":"Not Found","message":"No message available","path":"/"}
    

    原理

    Nginx

    • 首先根据client_header_buffer_size分配Request Header的Buffer (默认1K bytes)

    • 如果分配的Buffer无法容纳Request Header (通常都会小于1K bytes)

    • 那么根据large_client_header_buffers分配新的Buffer (默认1K bytes)

    • 如果分配的Buffer仍然无法容纳Request Header

    • 那么就会返回错误 414 Request-URI 太长 / 400 请求出错

    因此可以得到这两个影响Request Header Buffer的配置修改策略如下

    • 如果请求中的Header都很大 那么应该增大client_header_buffer_size 因为能减少一次内存分配

    • 如果请求中只有少量请求Header很大 那么应该增大large_client_header_buffers 因为能减少无谓的内存开销

    Java

    Key Default Value Description
    server.max-http-header-size 8KB Maximum size of the HTTP message header.

    优化

    • 方法1 拆分GET接口 参数分批并行访问
    # 过去
    GET params 1000
     
    # 优化
    [GET params 500, GET params 500] <= 并行
    
    • 方法2 使用POST接口 参数放至Body传递
    # 过去
    GET params 1000
    
    # 优化
    POST params 1000 (body)
    
    • 方法3 欢迎您的经验和留言

    参考

    相关文章

      网友评论

          本文标题:记一个Nginx线上问题

          本文链接:https://www.haomeiwen.com/subject/dhhykktx.html