关于redis短连接问题

场景:

PHP通过phpredis(https://github.com/phpredis/phpredis)循环执行如下操作:

 

 

发现connect会出现大量超过1s的情况,甚至超过3s;但是,如下图抓包所示:两次请求之间间隔了3s才发送syn请求,并且没有失败,也就是说,并非syn丢包所致,而是因为某种原因导致根本没有发送syn包;但是外部表现却是connect花费了很多时间(3s);

所以,从此推断,连接超时未必就一定是网络的问题,你们究竟会是什么原因导致client端3s后才发送syn的呢?

 

阅读源码发现: redis的connect用的是php提供的connect方法:php_stream_xport_create

其实,fsockopen用的也是该方法,如此的话,不放通过如下脚本直接测试connect:

结果如下:

  1. connect超过1s的还挺不少的
  2. 前面300多次的时候连续出了好几次超过1s的,你们怎么会从374到13489一直没出错呢?而且,运行程序的时候也能感觉到,从第374到第13489花费时间很短的,难道这个区间根本没有发生真正的连接? strace 跟踪统计发现,确实connect了,就是说,一般情况下,connect是很快的
  3. 该问题可能发生在PHP中,也可能发生在glibc中,也可能发生在系统层面,排查办法:
    1. 写一个C的,如果不出现问题,那么就是PHP的问题;如果依然如此,很可能是系统问题

让go get 支持gitlab

参考文章: https://baokun.li/archives/go-get-proxy/

在你的nginx中添加配置:

注意:修改你自己的域名

另:

  1. 可能你自己的gitlab没有配置https,那么可以给go get 添加 -insecure 选项即可
  2. 可能你的gitlab仓库需要输入用户名和密码,那么你可以改成public的就好了

 

关于docker

  1. docker create -it 其中 -it选项,如果没有的话,docker exec 进去,top时会报 TERM environment variable not set. 错误 ; 其实没有关系,手动 export TERM=xterm-256color 就可以了;其实, -it 选项和1号进程为 /bin/bash 是密切相关的; 如果1号进程不是 /bin/bash 的话,-it选项没有屁用
  2. docker 的CMD 其实是1号进程,一定不能立即就会退出的进程,如: service sshd start 就不行,如下脚本就可以:

     
  3. 容器可以自杀: 容器内进程使用root kill -9 1 默认是杀不死1号进程的,但是:
    当strace -p  1 的时候,kill -9 1 是可以杀死1号进程的 (难道说这是个bug?)
    因为docker stop时是先给1号进程发送sigterm,是在不行才kill -9 ; 所以,1号进程最好能合理处理sigterm信号,最后退出;然而,容器内的root进程是有权限给1号进程发送sigterm信号的,所以,容器自杀其实是很方便的
  4. 改进版的1号进程
    myinit.c

    gcc -o myinit myinit.c
    myinit.sh

  5. 其实还不够
    你会慢慢发现,ssh连接失败,因为:sshd接到连接请求之后,检查是否session太多了(默认最大10个),超过了就不伺候了,直接断开; 为什么会太多了?sshd每次接到连接请求,会fork => fork (两次fork)出来一个子进程处理请求,就因为是两次fork,这个新的sshd进程便“过继”给了1号进程;但是上面的1号进程还不够成熟,不会带孩子,当这个新的sshd进程退出的时候,就需要1号进程来做一些处理(如:清理进程表项),但是1号进程还不会,于是新的sshd进程会处于 <defunct>状态;而sshd的祖先还以为该session还没结束,就不再接受新的请求了,解决办法:添加信号处理,如下:

    参考资料:
    https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/
    https://github.com/phusion/baseimage-docker/blob/rel-0.9.16/image/bin/my_init
    dockerd 提供了init 和init-path的选项,允许配置是否启动一个指定的(默认的)init进程, 该进程就是为了转发信号和收割僵尸进程 的
  6. 上面sshd对于连接请求是两次fork的说法不太对,见下图:

    99、134进程并没有立即退出(不过,一旦意外退出,则 101、136将会被1号进程收养)
    还有一种情况为:sshd被restart了,这时候30号进程退出,99、134被1号进程收养,如下:

    由于我重启了sshd,再次连接就会失败,如下:

    为什么呢?
    稍后再查,至少可以确定的是,启动容器时候启动的sshd是可以正常服务的,登录进去重启的sshd是不能正常服务的

 

see also : https://docs.docker.com/engine/examples/running_ssh_service/

 

关于docker的内存限制:

  1. 如果每个docker容器限制最大使用4G,则可能会使用超过4G,(似乎是使用了交换分区了)
  2. 如果宿主机有64G内存,则允许docker容器内存总和大于64G,(这个不会也和交换分区有关吧)
  3. 文档说–memory-swap=-1 就禁止使用交换分区了,但是测试发现还是使用了1倍内存的交换分区

缅怀一下阿里云云引擎

 

学习一下人家下线产品是咋写的:

 

关于httpdns

概要

httpdns就是通过http的方式进行域名解析;阿里云有提供httpdns服务(目前2016-4-9 还处于公测阶段,需要申请公测资格才能用)。

传统dns解析存在的问题:

  1. 由于传统dns解析采用udp方式,而且是明文,所以
    1. 可能会被篡改
    2. 可能会被投毒(什么叫“投毒”?且看下文)

httpdns的实现原理:

  1. 通过http的方式进行域名解析,如:
  2. 通过设置http host header的方式发起http请求,如:

 

问题:

  1. httpdns server的域名如何解析?
    httpdns server 不通过域名提供服务,(只能)直接通过一个固定IP提供服务;服务提供商有足够的手段让这个IP不会出现宕机,而且世界各地(或者是全国各地)访问都能很快(就近访问),这个IP在世界上存在多份。
  2. 如何保证连接的这个ip是没被劫持呢?
    1. 或许可以给这个IP买个https证书,https证书提供商是可以给IP颁发证书的(比较少见),不过可能贵的多

 

优点:(参考文档: https://www.aliyun.com/product/httpdns?spm=5176.7960203.223922.4.2JohAO

  1. 防劫持
  2. 避免dns服务商莫名其妙的cache,可以做到立即修改理解生效
  3. 精准调度

问题:

  1. https请求问题及解决方案: https://help.aliyun.com/document_detail/httpdns/practice/https.html?spm=5176.7947101.220063.5.9DtXGS
    1. 这里回避了单个IP上多个https证书的问题,或许也可以通过钩子解决,但是不一定存在这样的钩子; ssl握手的时候,必须告知正确的host信息,否则,服务器无法知道该返回哪个证书,而不仅仅是验证证书的问题
  2. httpdns只适用于app、client的情况,对于web浏览器是不行的,还好现在大家都是在玩app了;
  3. 对于app里面适用webview的情况需要特殊处理一下:https://help.aliyun.com/document_detail/httpdns/practice/webview.html?spm=5176.dochttpdns/user-guide/resolve-stats.6.127.VFTz3N
  4. 对于通过react native来开发app的情况不知道是否方便使用

 

dns投毒:

因为域名解析是udp的,只要我已dns server的ip不断地向你的机器发送域名解析结果响应的话,你可能就会认为确实是dns server响应的结果;当然,有几个关键点需要注意:

  1. 用户确实需要解析某域名(一般来讲,解析完了会cache一段时间的)
  2. 伪造的响应里面是需要包含用户正在查询的域名的,域名不匹配自然不会被接受
  3. 用户发起请求的端口号(2字节)是随机的,响应的数据包需要能匹配上这个端口,否则不会被接受
  4. 用户发起的请求有一个随机的请求标识(2字节),响应的数据包需要能匹配上这个请求标识,否则不会被接受
  5. 我咋感觉这个难度其实并不算小啊,除非你是个中间人

httpdns示例:

 

更多参考:

全局精确流量调度新思路-HttpDNS服务详解: http://www.zmke.com/i/8705.html

渗透测试:内网DNS投毒技术劫持会话:http://www.freebuf.com/articles/web/43157.html

http://www.onedns.net/  需要特殊的dns客户端

加密的dns: https://www.opendns.com/about/innovations/dnscrypt/   需要特殊的dns客户端

wireshark分析dns协议: http://blog.csdn.net/hunanchenxingyu/article/details/21488291

dns协议格式: http://cjhust.blog.163.com/blog/static/1758271572014111875652363/

关于shell一些小知识点

关于 [[]] 和 [] 的区别

实例1:

说明:

[]  和 [[]]  是不同的语法;

对于 [

事实上, bash 中没有 [] 语法, [ 是一个命令,出于美观考虑,要求有一个 ] 与之配对; 所以 [ 的前后是要有空格的

对于 [[

[[]] 是bash的内建语法

  1. 如果是 == ,则右边被视为 Pattern; 如果是 =~ ,则右边视为正则; 也就是说,左边和右边是不等价的
  2. [[]] 允许内部 与、或、非; 如: [[ 1 == 1 && 2 == 2 ]]; 而 [] 则不可以,只能: [ 1 == 1 ] && [ 2 == 2 ]

bash基本概念

  1. bash中有保留字(reserved word)和元字符(meta charactor)的区别的,这个很重要
    1. 关键字:
    2. 元字符:
    3. xx
  2. 对于关键字,和其他非元字符的字符都需要用空白字符分开,否则,关键字就识别不出来了; 因为元字符是被特殊对待的,所以,关键字挨着元字符是允许的,所以,如果分不清关键字和元字符的话,就不知道什么时候需要用空白符分隔,什么时候不需要空白符分隔

 

 

man bash

关于元字符、保留字

关于 花括弧

 

命令替换