php-fpm reload 时 nginx 出现 error log 分析

起因

每次 Jenkins 发版的时候 nginx 总会有几个 error log 出现,量也不是很大,通过时间点查看 access log,发现 http status 是 502。

2019/08/08 10:07:35 [error] 11346#0: *395555896 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 100.79.15.33, server: xxxxxx, request: "GET /api/v2/current-ad?language=zh_CN HTTP/1.1", upstream: "fastcgi://unix:/tmp/php-cgi-56.sock:", host: "xxxxxx"
2019/08/08 10:07:35 [error] 11347#0: *395557146 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 100.79.15.23, server: xxxxxx, request: "POST /hw/v2/scene/bundle/lists HTTP/1.1", upstream: "fastcgi://unix:/tmp/php-cgi-56.sock:", host: "xxxxxx"

解决方案

通过查找资料找到了需要配置的参数:

process_control_timeout = 10

参数含义是 设置子进程接受主进程复用信号的超时时间,控制子进程处理来自master的信号的时间,默认为 0 如果正在处理请求, 很可能会收到错误报警。

现在我们需要在 php-fpm.conf [global] 配置块里面配置,我这里配置为 10s,没有配置了 [global] 里面会导致 php-fpm 启动失败,切记!
配置完成之后需要 reload 加载最新配置,第一次 reload 还是会有 error 的,因为我们的配置还没有生效,之后的 reload 就可以解决此问题,这就可以放心的发版了!

Linux 平台安装 MongoDB

说明

MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。

步骤

1. 下载

https://www.mongodb.com/download-center/community
Version 选择最新的稳定版, OS 选择 Linux 64-bit legacy x64,会看到下载地址。

cd /usr/local/src
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.11.tgz

2. 解压

tar zvxf mongodb-linux-x86_64-4.0.11.tgz
mv mongodb-linux-x86_64-4.0.11 /usr/local/mongodb

3. 文件说明

Name Comments
bsondump 导出 bson 结构
install_compass compass 是一个 GUI 的管理工具
mongo 客户端(相当于 mysql.exe)
mongod 服务端(相当于 mysqld.exe)
mongodump 整体数据库导出(相当于 mysqldump)
mongofiles 操作 GridFS 文件
mongoreplay 重放流量到其他实例
mongos 路由器(分片时用)
mongotop 耗时数据统计
mongoexport 导出易识别的 json 或 csv,方便用代码处理
mongoimport 导入 json, csv 等格式
mongorestore 数据库整体导入,与 mongodump 相结合
mongostat instance 的状态统计,类似 vmstat

4. 启动

MongoDB 的可执行文件位于 bin 目录下,所以可以将其添加到 PATH 路径中:

export PATH= /usr/local/mongodb/bin:$PATH

MongoDB的数据存储在data目录的db目录下,但是这个目录在安装过程不会自动创建,所以你需要手动创建data目录,并在data目录中创建db目录。

mkdir -p /data/db

最简单的启动,前台运行

cd /usr/local/mongodb/bin
./mongo

后台运行

cd /usr/local/mongodb/bin
./mongod --dbpath /data/db --logpath /var/log/mongodb.log --logappend --fork --port 27017
Param Comments
--dbpath 数据存储目录
--logpath 日志存储目录
--port 运行端口(默认27017)
--fork 后台进程运行

5. 注意点

mongodb非常的占磁盘空间, 如果你用虚拟机练习,可能空间不够,导致无法启动.
可以用 --smallfiles 选项来启动,
将会占用较小空间 400M左右.

Linux统计文件夹、文件数量的命令

查看当前目录下的文件数量(不包含子目录中的文件)

ls -l|grep "^-"| wc -l

查看当前目录下的文件数量(包含子目录中的文件) 注意:R,代表子目录

ls -lR|grep "^-"| wc -l

查看当前目录下的文件夹目录个数(不包含子目录中的目录),同上述理,如果需要查看子目录的,加上R

ls -l|grep "^d"| wc -l

查询当前路径下的指定前缀名的目录下的所有文件数量

例如:统计所有以“20161124”开头的目录下的全部文件数量

ls -lR 20161124*/|grep "^-"| wc -l

  

对每个命令参数做一下说明备注:

ls -l
该命令表示以长列表输出指定目录下的信息(未指定则表示当前目录),R代表子目录中的“文件”,这个“文件”指的是目录、链接、设备文件等的总称

grep "^d"表示目录,"^-"表示文件

wc -l
表示统计输出信息的行数,因为经过前面的过滤已经只剩下普通文件,一个目录或文件对应一行,所以统计的信息的行数也就是目录或文件的个数

记一次 Laravel MethodNotAllowedHttpException 问题排查

问题描述

线上一个 laravel 4.2 的项目有 Exception 产生,通过查看 log 发现每天会有 2 条左右出现,量也不大,通过日志能看出是 MethodNotAllowedHttpException 异常,下面记录一下解决过程。

[2019-05-17 06:04:38] Oregon.ERROR: Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException in /******/endpoint/bootstrap/compiled.php:5753
Stack trace:
#0 /******/endpoint/bootstrap/compiled.php(5749): Illuminate\Routing\RouteCollection->methodNotAllowed(Array)
#1 /******/endpoint/bootstrap/compiled.php(5727): Illuminate\Routing\RouteCollection->getOtherMethodsRoute(Object(Illuminate\Http\Request), Array)
#2 /******/endpoint/bootstrap/compiled.php(5051): Illuminate\Routing\RouteCollection->match(Object(Illuminate\Http\Request))
#3 /******/endpoint/bootstrap/compiled.php(5039): Illuminate\Routing\Router->findRoute(Object(Illuminate\Http\Request))
#4 /******/endpoint/bootstrap/compiled.php(5031): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
#5 /******/endpoint/bootstrap/compiled.php(720): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#6 /******/endpoint/bootstrap/compiled.php(696): Illuminate\Foundation\Application->dispatch(Object(Illuminate\Http\Request))
#7 /******/endpoint/bootstrap/compiled.php(7803): Illuminate\Foundation\Application->handle(Object(Illuminate\Http\Request), 1, true)
#8 /******/endpoint/bootstrap/compiled.php(8410): Illuminate\Session\Middleware->handle(Object(Illuminate\Http\Request), 1, true)
#9 /******/endpoint/bootstrap/compiled.php(8357): Illuminate\Cookie\Queue->handle(Object(Illuminate\Http\Request), 1, true)
#10 /******/endpoint/bootstrap/compiled.php(11154): Illuminate\Cookie\Guard->handle(Object(Illuminate\Http\Request), 1, true)
#11 /******/endpoint/bootstrap/compiled.php(657): Stack\StackedHttpKernel->handle(Object(Illuminate\Http\Request))
#12 /******/endpoint/public/index.php(48): Illuminate\Foundation\Application->run()
#13 {main} [] []

排查过程

  通过查找 nginx access log 找到对应的信息,是 post 请求 index.php,我用 postMan 来进行模拟并没有复现这个 exception,我拿到的只是一个 200 的 Response,并不是 500,这应该是扫描器批量扫描的,或者是 spider 爬的,并没有走域名,而是从 ip 直接访问。

**.93.2.** **.71.95.** 182.61.178.228 - "17/May/2019:06:04:39 +0800" "POST /index.php HTTP/1.1" 453 4534 0.680 500 unix:/tmp/php-cgi-72.sock - 0.004 "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:28.0) Gecko/20100101 Firefox/28.0" 

查找 nginx error log 没有对应的 log,问题到这里就僵住了,返回去看 exception log 找到抛出异常之前最后一个执行的方法

Illuminate\Routing\RouteCollection->getOtherMethodsRoute

/* 代码路径 */
/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php  :186
    /**
     * Get a route (if necessary) that responds when other available methods are present.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  array  $others
     * @return \Illuminate\Routing\Route
     *
     * @throws \Symfony\Component\Routing\Exception\MethodNotAllowedHttpException
     */
    protected function getOtherMethodsRoute($request, array $others)
    {
        if ($request->method() == 'OPTIONS')
        {
            return (new Route('OPTIONS', $request->path(), function() use ($others)
            {
                return new Response('', 200, array('Allow' => implode(',', $others)));

            }))->bind($request);
        }

        $this->methodNotAllowed($others);
    }

  看到这就大体明白了,如果 method 是 OPTIONS 会有 200 的正常 Response,否则就抛出错误,猜测 Http method 肯定是一个比较冷门的,导致框架报错,从 postMan 找一个比较冷门的 method UNLOCK 试了一下,果然状态 500,成功复现。

  这里有一段小插曲:为什么状态是 500 呢,应该是 405 才对,查看代码发现处理 error 的逻辑里面调用了一个已经优化掉的日志类,去掉那一行调用,一切正常。

- 阅读全文 -

filebeat 安装 + 配置

说明

公司业务日志系统是 ELK 的技术栈,每个机器都需要有 agent 来负责收集,filebeat 是比较不错的选择。

安装步骤

Ubuntu

curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.5.4-amd64.deb
sudo dpkg -i filebeat-6.5.4-amd64.deb

CentOS

curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.5.4-x86_64.rpm
sudo rpm -vi filebeat-6.5.4-x86_64.rpm

官方文档:
https://www.elastic.co/guide/en/beats/filebeat/index.html
https://www.elastic.co/guide/en/beats/filebeat/6.5/filebeat-installation.html

配置文件路径

/etc/filebeat/filebeat.yml

配置文件内容

filebeat.inputs:
# Nginx access log #
- type: log
  paths:
    - /www/wwwlogs/cloud-bj.yeelight.com.log
  fields:
    region: Beijing
    type: nginx-log

# Nginx error log #
- type: log
  paths:
    - /www/wwwlogs/cloud-bj.yeelight.com.error.log
  fields:
    region: Beijing
    type: cloud-error-log

# PHP error log #
- type: log
  paths:
    - /www/wwwlogs/php_errors.log
  fields:
    region: Beijing
    type: php-errors-log

# Laravel Framework log #
- type: log
  paths:
    - /www/wwwroot/cloud-manage/app/storage/logs/laravel-*.log
  fields:
    region: Beijing
    type: cloud-manage-laravel

  multiline.pattern: '^\['
  multiline.negate: true
  multiline.match: after

# Single log DAU #
- type: log
  paths:
    - /www/wwwroot/cloud-manage/app/storage/logs/single-log-*.log
  fields:
    region: Beijing
    type: single-log

output.logstash:
  hosts: ["192.168.0.63:5044"]

log 文件路径

/var/log/filebeat

filebeat 开机启动

vim /etc/rc.local
#!/bin/bash
/etc/init.d/filebeat start
chmod +x /etc/rc.local