首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >nginx 常见问题记录

nginx 常见问题记录

原创
作者头像
CIKEY
修改2020-08-02 23:33:21
1.1K0
修改2020-08-02 23:33:21
举报
文章被收录于专栏:进击的全栈进击的全栈

一、location 中的 if 地狱

Directive if has problems when used in location context, in some cases it doesn’t do what you expect but something completely different instead. In some cases it even segfaults. It’s generally a good idea to avoid it if possible.

The only 100% safe things which may be done inside if in a location context are:

return ...;

rewrite ... last;

官方文档指明,location if语句中只有实用return 和 rewrite指令是绝对安全的。但是如果某些情况必须使用if 语句进行条件判断怎么办呢?需要记住一下几点:

  • 当多个if条件判断同时满足时,只有最后一个if中的语句会被执行。因此若匹配前一个if语句后,不希望再往下继续匹配时,需要使用break结束;
  • proxy_pass 和 try_files 可能因为if语句不能正常执行;
  • nginx中不支持else、&& 和 || 语法,另外,nginx中if 语句也不支持嵌套,需要使用变量来构造;

二、access_log 和 error_log的路径能否使用变量?

某些场景下我们需要根据条件来区分nginx日志打印的路径,首先想到的就是能否使用如下语句呢?

access_log /home/path/${server_name}.access.log;

在高版本的nginx中允许access_log中使用变量,但是会有如下限制:

  • 日志文件用“工作进程”创建,所以需要在日志目录有创建文件的权限。
  • 无法使用写入缓冲。
  • 由于经常使用的文件描述符会被缓存,在指令open_log_file_cache的参数valid指定的时间内,还会写入旧文件中。
  • 每次写入日志时,会检查root目录是否存在。不存在,则不会创建日志。

简而言之,日志存在无法写入的可能,并且由于没有写入缓存,在请求量较大的场景会造成性能问题。

因此并不建议在access_log的路径中使用变量名。那怎样才能满足分不同路径打印的需求呢?access_log 支持可选参数 if=condition, 例如下面的官方例子,当返回码为2xx或3xx时不会打印日志,其他情况下的日志会打印到/path/to/access.log文件中:

map $status $loggable {
    ~^[23]  0;
    default 1;
}

access_log /path/to/access.log combined if=$loggable;

error_log 路径不支持变量。变量一般是在http请求中使用,而error_log并不限于http请求使用,且应该保证所有关键的错误日志都能打印成功,便于定位问题。

三、自定义头部写法规范

在nginx中使用自定义头部不限制字母的大小写,但需要注意尽量使用中划线,若在必须使用下划线的情况下,需要设置 underscores_in_headers on;否则nginx会认为该头部不合法,由 ignore_invalid_headers 指令判断是否忽略该头部。

nginx读取自定义头部的变量为$http_{name}, name为头部名称的小写,且用下划线代替中划线即可。

四、慎用proxy_next_upstream

在不了解proxy_next_upstream机制时可能会踩到很多坑,比如服务出现了错误或超时,nginx却没有按照预期自动进行重试;或者类似创建订单或支付类的写接口,客户端明明只发送了一次请求,却因为nginx的重试,后台创建了多个相同的订单而引发线网问题等。

proxy_next_upstream指令指明了请求在什么情况会被重新发送到另外的server。

默认只有当连接上游服务出错或者超时时会重试,若需要对某些特定的http状态码进行重试,则需要指定http_500、http_404等。

但是通常情况下POST, LOCK, PATCH方法不会被转发到另一台server重试,需要显示设置non_idempotent才行。

但是生产环境一般不建议开启non_idempotent,无论是timeout还是http_500都可能是后台已经接受过一次请求了,若nginx再次转发重试就会造成重复写入的问题。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、location 中的 if 地狱
  • 二、access_log 和 error_log的路径能否使用变量?
  • 三、自定义头部写法规范
  • 四、慎用proxy_next_upstream
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档