启动nginx状态页

nginx 内建了一个状态页,对于想了解nginx的状态以及监控nginx非常有帮助。

在你的 nginx.conf 配置的server中添加如下配置:

location /nginx_status {
    stub_status on;
    access_log off;
    allow 192.168.10.0/24;
    deny all;
}

然后重启 nginx,即可成功。

你可能在重启的时候遇到

unknown directive "stub_status"

这是因为nginx没有加上http_stub_status_module,需要重新安装这个插件:

./configure --with-http_stub_status_module

访问该网页,可以看到类似如下的信息:

Active connections: 1998 
server accepts handled requests
1189721 1189721 2667471 
Reading: 2 Writing: 10 Waiting: 1980

说明:

  • Active connection -活跃的连接数量
  • server accepts handled requests 总共处理了1189721个连接,成功创建了1189721次握手,总共处理了2667471个请求
  • Reading——读取客户端的连接数
  • Writing——响应数据到客户端的数量
  • Waitting——开启keep-alive的情况下,这个只等于active-(Reading+Writing),意思就是nginx已经处理完正在等候下一次请求指令的驻留连接

反向代理 GitHub Pages

我的这个 blog 一直托管在 github 上。因为担心访问问题(貌似 Github 原本就是 GFW 屏蔽的?),配置了一个免费的 CDN:https://www.incapsula.com/,不得不说,其实还是不错的,可以避免访问不稳定的问题。缺点在于访问速度确实慢了,大概有1300-2000ms延迟。

手头上刚好有比较好的资源,就做了一个反向代理,效果不错,目前延迟在120-400ms,已经满足了。

配置反代也非常简单,就两步,DNS 重定向和 nginx 反代:

dns重定向

配置DNS重定向到目标服务器。

nginx

server {
    listen       80;
    server_name  blog.kelu.org;

    access_log off; #access_log end
    error_log /dev/null; #error_log end

    location / {
           proxy_pass         http://kelvinblood.github.io;
           proxy_redirect     off;
           proxy_set_header   Host                        $host;
           proxy_set_header   X-Real-IP               $remote_addr;
           proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    }
}

配置说明:

proxy_set_header Host $host 设置请求头的Host为反向代理服务器的Host

proxy_set_header X-Real-IP $remote_addr 设置请求头的X-Real-IP为客户端真实IP

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for 把请求来源的IP添加到请求头的X-Forwarded-For字段

X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP代理或者负载均衡服务器时才会添加该项。 它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍。 标准格式如下:X-Forwarded-For: client1, proxy1, proxy2。

Hubot 脚本与开发文档一 中文

每次看英文文档都有点头疼,做了一些简要的翻译给自己看。 原文请看https://hubot.github.com/docs/scripting/

目录:

  • 接收和回复
  • 给指定群组或用户的消息
  • 捕获数据
  • 进行HTTP调用
  • 随机
  • Topic
  • 进入和离开聊天室
  • 自定义房间人员
  • 环境变量
  • 依赖
  • HTTP监听器
  • 事件
  • 错误处理
  • 记录脚本
  • 持久化
  • 脚本

    • 加载脚本
    • 共享脚本
  • 中间件

    • 监听中间件
    • 接收中间件
    • 回复中间件
  • 测试

正文:

安装好hubot后,根目录下会生成一个 scripts 目录,里面有个可用的 demo 文件example.coffee,大致如下:

# Description:
#   Example scripts for you to examine and try out.
#
# Notes:
#   They are commented out by default, because most of them are pretty silly and
#   wouldn't be useful and amusing enough for day to day huboting.
#   Uncomment the ones you want to try and experiment with.
#
#   These are from the scripting documentation: https://github.com/github/hubot/blob/master/docs/scripting.md

module.exports = (robot) ->

 robot.hear /kelutest/i, (res) ->
   res.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"
  #
  # robot.respond /open the (.*) doors/i, (res) ->
  #   doorType = res.match[1]
  #   if doorType is "pod bay"
  #     res.reply "I'm afraid I can't let you do that."
  #   else
  #     res.reply "Opening #{doorType} doors"

要使得你编写的script生效,需要满足一下三个条件:

  • 在scripts文件夹中
  • .coffee 或 .js 文件
  • 导出一个方法

      module.exports = (robot) ->
        # your code here
    

接收和回复

module.exports = (robot) ->
  robot.hear /badger/i, (res) ->
    res.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"

  robot.respond /open the pod bay doors/i, (res) ->
    res.reply "I'm afraid I can't let you do that."

  robot.hear /I like pie/i, (res) ->
    res.emote "makes a freshly baked pie"
  • hear 所有匹配信息
  • send 发送消息
  • respond 群组消息中只处理@自己的信息
  • reply 群组消息中回复特定人的消息

给指定群组或用户的消息

可以使用messageRoom函数发送到指定的房间或用户,可以明确地指定用户名(对于管理员/管理员),或者使用响应对象将私人消息发送到原始发件人。

  robot.respond /I don't like Sam-I-am/i, (res) ->
    room =  'joemanager'
    robot.messageRoom room, "Someone does not like Dr. Seus"
    res.reply  "That Sam-I-am\nThat Sam-I-am\nI do not like\nthat Sam-I-am"

  robot.hear /Sam-I-am/i, (res) ->
    room =  res.envelope.user.name
    robot.messageRoom room, "That Sam-I-am\nThat Sam-I-am\nI do not like\nthat Sam-I-am"

捕获数据

res.match 存有 match 传入消息与正则表达式的结果。这是一个数组,索引起始是0。比如:

  robot.respond /open the (.*) doors/i, (res) ->
    doorType = res.match[1]
    if doorType is "pod bay"
      res.reply "I'm afraid I can't let you do that."
    else
      res.reply "Opening #{doorType} doors"

进行HTTP调用

Hubot可以集成使用第三方API。 通过 node-scoped-http-client 插件的robot.http,可以进行http调用。 最简单的情况如下:

get:

   robot.http("http://blog.kelu.org")
     .get() (err, res, body) ->
       # your code here

post:

    data = JSON.stringify({
      foo: 'bar'
    })
    robot.http("http://blog.kelu.org")
      .header('Content-Type', 'application/json')
      .post(data) (err, res, body) ->
        # your code here     

处理错误:

  robot.http("https://midnight-train")
    .get() (err, res, body) ->
      if err
        res.send "Encountered an error :( #{err}"
        return
      # your code here, knowing it was successful            

如果需要处理返回头部信息,应该如下操作:

  robot.http("https://midnight-train")
    .get() (err, res, body) ->
      # pretend there's error checking code here

      if res.statusCode isnt 200
        res.send "Request didn't come back HTTP 200 :("
        return

      rateLimitRemaining = parseInt res.getHeader('X-RateLimit-Limit') if res.getHeader('X-RateLimit-Limit')
      if rateLimitRemaining and rateLimitRemaining < 1
        res.send "Rate Limit hit, stop believing for awhile"

      # rest of your code
      res.send "Got back #{body}"

json

我们可以使用 json.parse 进行解析,有可能得到非JSON,为了安全起见,应该检查Content-Type ,并在解析时捕获错误。

  robot.http("https://midnight-train")
    .header('Accept', 'application/json')
    .get() (err, res, body) ->
      # err & response status checking code here

      if response.getHeader('Content-Type') isnt 'application/json'
        res.send "Didn't get back JSON :("
        return

      data = null
      try
        data = JSON.parse body
      catch error
       res.send "Ran into an error parsing JSON :("
       return

      # your code here

xml

比较麻烦,可以参考以下几个库:

截图

参考以下库

  • cheerio (familiar syntax and API to jQuery)
  • jsdom (JavaScript implementation of the W3C DOM)

高级HTTP和HTTPS设置

如上所述,hubot使用 node-scoped-http-client 来提供一个简单的接口来进行HTTP和HTTPS请求。

如果需要更直接地控制http和https,则将第二个参数传递给robot.http ,该参数将被传递给节点robot.http -http-client,该参数将传递给http和https:

  options =
    # don't verify server certificate against a CA, SCARY!
    rejectUnauthorized: false
  robot.http("https://midnight-train", options)

如果 node-scoped-http-client 不满足需求,我们也可以直接使用http和https ,或者其他节点库(如request/request) 。

随机

lulz = ['lol', 'rofl', 'lmao']

res.send res.random lulz

Topic

可以修改房间的主题

  module.exports = (robot) ->
    robot.topic (res) ->
      res.send "#{res.message.text}? That's a Paddlin'"

进入和离开聊天室

enterReplies = ['Hi', 'Target Acquired', 'Firing', 'Hello friend.', 'Gotcha', 'I see you']
leaveReplies = ['Are you still there?', 'Target lost', 'Searching']

module.exports = (robot) ->
  robot.enter (res) ->
    res.send res.random enterReplies
  robot.leave (res) ->
    res.send res.random leaveReplies

nginx location 总结、rewrite 规则写法与其它通用配置

本文转自《nginx配置location总结及rewrite规则写法》《nginx服务器安装及配置文件详解》,有删减。

1. location正则写法

示例:

location  = / {
  # 精确匹配 / ,主机名后面不能带任何字符串
  [ configuration A ]
}
location  / {
  # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
  # 但是正则和最长字符串会优先匹配
  [ configuration B ]
}
location /documents/ {
  # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
  # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
  [ configuration C ]
}
location ~ /documents/Abc {
  # 匹配任何以 /documents/Abc 开头的地址,匹配符合以后,还要继续往下搜索
  # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
  [ configuration CC ]
}
location ^~ /images/ {
  # 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。
  [ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ {
  # 匹配所有以 gif,jpg或jpeg 结尾的请求
  # 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则
  [ configuration E ]
}
location /images/ {
  # 字符匹配到 /images/,继续往下,会发现 ^~ 存在
  [ configuration F ]
}
location /images/abc {
  # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在
  # F与G的放置顺序是没有关系的
  [ configuration G ]
}
location ~ /images/abc/ {
  # 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用
    [ configuration H ]
}
location ~* /js/.*/\.js
  • =开头表示精确匹配 如 A 中只匹配根目录结尾的请求,后面不能带任何字符串。
  • ^~ 开头表示uri以某个常规字符串开头,不是正则匹配
  • ~ 开头表示区分大小写的正则匹配;
  • ~* 开头表示不区分大小写的正则匹配
  • / 通用匹配, 如果没有其它匹配,任何请求都会匹配到

顺序 no优先级:


启动php-fpm状态页

上一篇写了 nginx 状态页,这一篇写一下 php-fpm 状态页。

开启

在你的 php-fpm.conf 的项目配置中打开如下配置:

pm.status_path = /_status 

重启 php-fpm。

nginx 中也添加配置,大概如下面这样:

 location = /_status {
     fastcgi_pass                               unix:/var/local/fpm-pools/wechat/php-fpm.sock;
     include                                    fastcgi.conf;
     fastcgi_param           SCRIPT_NAME        /_status;
 }

将请求传给socket,再由php-fpm进行内容生成。生成的内容大致如下:

pool:                 wechat
process manager:      dynamic
start time:           06/May/2017:14:59:51 +0800
start since:          363832
accepted conn:        27141
listen queue:         0
max listen queue:     0
listen queue len:     0
idle processes:       2
active processes:     1
total processes:      3
max active processes: 10
max children reached: 0
slow requests:        65

内容解释:

  • pool – fpm池子名称,大多数为www
  • process manager – 进程管理方式,值:static, dynamic or ondemand. dynamic
  • start time – 启动日期,如果reload了php-fpm,时间会更新
  • start since – 运行时长
  • accepted conn – 当前池子接受的请求数
  • listen queue – 请求等待队列,如果这个值不为0,那么要增加FPM的进程数量
  • max listen queue – 请求等待队列最高的数量
  • listen queue len – socket等待队列长度
  • idle processes – 空闲进程数量
  • active processes – 活跃进程数量
  • total processes – 总进程数量
  • max active processes – 最大的活跃进程数量(FPM启动开始算)
  • max children reached - 大道进程最大数量限制的次数,如果这个数量不为0,那说明你的最大进程数量太小了,请改大一点。
  • slow requests – 启用了php-fpm slow-log,缓慢请求的数量

另外 php-fpm 状态页还可以带参数,可以带get参数json、xml、html,并且可以分别和full做一个组合。

full详解

  • pid – 进程PID,可以单独kill这个进程. You can use this PID to kill a long running process.
  • state – 当前进程的状态 (Idle, Running, …)
  • start time – 进程启动的日期
  • start since – 当前进程运行时长
  • requests – 当前进程处理了多少个请求
  • request duration – 请求时长(微妙)
  • request method – 请求方法 (GET, POST, …)
  • request URI – 请求URI
  • content length – 请求内容长度 (仅用于 POST)
  • user – 用户 (PHP_AUTH_USER) (or ‘-’ 如果没设置)
  • script – PHP脚本 (or ‘-’ if not set)
  • last request cpu – 最后一个请求CPU使用率。
  • last request memorythe - 上一个请求使用的内存

php-fpm状态页可以使用zabbix或者nagios统一进行监控。