nginx 之unix socket

缘起:

曾经在nginx(1.7.4)两个地方配置过unix socket;一个是nginx日志,一个是fastcgi;但是,这两个地方有所不同。

关于日志的配置,通过unix socket (/dev/log) 写到本地的syslogd,如果syslogd重启了,则/dev/log 其实是被更新了的,但是nginx却不会自动重连,然后nginx就写log失败了。 如此,重启syslogd就得重启nginx,是多么“2”的一件事情啊!

关于fastcgi的配置,通过unix socket访问本地的php-fpm,如果php-fpm重启,则 unix socket不更新,自然影响不到nignx; 如果fpm stop then start,则unix socket会更新,但是,nginx却知道自动重连,也不会影响到nginx。(难道是因为该socket走的是stream的原因?)

注: 如果你不小心将socket文件配到了/tmp 下面,则socket文件可能是660的权限,nginx(用户如果和php-fpm不同)可能就没有权限连接该unix socket

nginx 之fail_over

问题: 默认情况下,nginx会自动failover,即: 其中一个上游服务器处理失败时会自动将请求转发到下一个上游服务器;有些情况下是不期望如此的;

但是这里没有区分上游服务器的失败原因,如果是连接失败,则自动fail_over 基本是没问题的;如果是已经发送了数据然后等待响应超时失败,可能并不想fail_over

 

避免failover的办法:

  1. 对于fastcgi: fastcgi_next_upstream off
  2. 对于proxy:  proxy_next_upstream off

如果把 proxy_next_upstream 写到fastcgi_pass 中是不会有效果的,虽然不会报错

 

可能在应用层来避免重复处理才是正道

 

关于tcp健康检查

方法1: connect then close

这种情况,上层应用会感知到一个连接的进入,并准备开始处理,然后便因为client端close而中止

方法2: send syn then receive syn-ack then send reset

这样的话,远端根本不需要完成一个tcp连接,也不会被上层应用感知到;这样需要更加底层的socket(raw socket)编程

方法3: send syn then receive syn-ack then send ack then send reset

2015-12-17 更新:

初写这篇文章时,阿里金融云SLB的tcp健康检查使用的是方法1,也是因此才写的该文章;今天发现阿里金融云SLB的tcp健康检查使用的是方法2,于是在此更新一下该文章。

2016-11-10 更新:

发现阿里金融云的SLB的tcp健康检查又不是方法2了, 阿里云文档上写的是方法2,实际上不是方法2,而是方法3,方法3更坑爹,有些web server会报client异常关闭连接

2018-8-2 更新:

SLB的HTTP模式下,健康检查允许关闭, TCP模式下不允许关闭健康检查;虽然允许设置检查其他端口来避免健康检查对某些服务的骚扰,但依然觉得很别扭;

2018-11-09更新:

对于HTTP服务,仅检查端口存活不大严格,如果进程假死,依然无法提供服务,但是端口是活的,所以,对于HTTP服务,通过HTTP请求来检查还是比较合理的,为了避免不必要的访问日志,可以对这种请求不记录访问日志

 

nmap 的半连接端口检查:

 

 

 

cgroup 学习

题记: cgroup早该学习了

缘起:

几十台虚拟机,没有资源限制,宿主机经常挂掉,不知道因为啥。

该看看cgroup了

  1. 上网查文档
  2. 安装:
  3. 配置
    /etc/cgconfig.conf 添加:

    注意: cpuset.mems = “0”;是需要的,否则不生效哦(稍后再看是咋回事儿)
    /etc/cgrules.conf 添加: (据说对子进程是生效的)
  4. 重启服务:

    cgconfig是配置服务, cgred是规则引擎daemon
  5. 测试:
    。。。 发现 /usr/bin/vagrant 启动的进程都放到了vagrant组中了,cpu只使用0、1,其他的都不会被用到
    修改配置文件后,重启两个服务,即可生效,可以立即影响到正在运行的进程

libcgroup 工作方式:

  1. cgconfig服务 其实是通过 /sbin/cgconfigparser 解析并load /etc/cgconfig.conf 以及 /etc/cgconfig.d/* ,把配置文件中需要mount的mount上去
  2. cgred服务其实是/sbin/cgrulesengd ;主要是listen /var/run/cgred.socket , 这个socket是个比较核心的东西,系统没启动一个进程(或者别的操作也会),就会通知到该socket,而/sbin/cgrulesengd就是要根据配置的规则把启动的那个进程添加(就是写一个文件那么的简单)到指定的cgroup中去
  3. 注意:
    1.  /sbin/cgrulesengd 的man中说他可以接收USR1信号,但是实际上把这个信号发过去,进程就直接死掉,连pid文件和lock文件都不会清理掉的
    2. 内存限制指的是对该组中所有进程占用内存之和的限制,oom触发在申请内存的时候,如果是后期加入的,不会在加入的时候触发oom; blkio 的限制也是组内共享的
    3. /cgroup/memory/memory.oom_control 为 1时 ,内存不够时不会杀死进程,但是申请内存的程序会hang住
    4. cgexec 不依赖cgrulesengd ,cgrulesengd偶尔会不太好使,比如:修改完配置文件之后忘记重启了,所以,建议直接使用 cgexec来测试
    5. 限制blkio时需要知道磁盘的主设备号和次设备号,查看方法: lsblk
    6. cgred 服务stop时,不会将添加到cgroup中的pid给移除掉,但是cgconfig服务stop时会移除所有的cgroup
    7. /etc/cgrules.conf 中controller部分的 ‘*’ 代表添加到所有的子系统中(如果配置了的话),但是测试发现,如果同时添加到cpuset,memory 子系统中,写 ‘*’  却只添加到了cpuset中了,明确些cpuset,memory 就好使(这种问题浪费了新人很多的时间)
    8. 当将进程加入某个group时,如果该进程没有在加入group之后发生内存(资源)申请时,则子系统的统计信息中是没有包含该进程的资源信息的,虽然该进程已经占用了很大的rss,内存子系统中的rss很有可能依然是零.(可能这根本就不是问题)

参考:

https://www.kernel.org/doc/Documentation/cgroups/memory.txt

http://www.cnblogs.com/yanghuahui/p/3751826.html

mkdir 之 mode

题记: 学习要细心

曾经,在php中要创建一个权限为 0777的目录:

应该问题不大,写完就交差了,测也不测;后来发现,创建的目录是 0755的,再检查一遍代码,确认是0777,不可能错的!可能是谁给修改成0755了吧?然后就做别的去了…

终于有一天,同事遇到了同样的问题,叫我过去看看,猜测可能和umask有关系,修改umask=0000(零零零零)后,终于创建出了0777的目录了,果然和umask有关系,有点儿坑die吧?

难道是PHP中添加了这种奇怪的逻辑? (写C的同学不要笑我,俺没写过C)

查看PHP源代码,发现PHP的mkdir直接调用的是glibc中的mkdir,没有做任何特殊处理,那么?

man 2 mkdir

有如下描述:

问题真相大白了。

我们知道命令行的mkdir -m 0777 能创建出来777的目录,难道命令行的mkdir用的不是glibc的mkdir?不太可能,参看: mkdir –help

很有可能mkdir在创建目录之后,chmod修改了目录的权限