Java 静态(static)方法读取 Nacos 配置中心

为了降成本节省服务器资源,需要将配置中心从 Apollo 切换到 Nacos,因为注册中心是 Nacos 直接复用集群即可。

问题描述

util 里面获取配置的方法都是 static 静态方法,这就导致了 @Value 根本获取不到 Nacos 里面的配置,所有都改成非静态方法改动很大,很不实际,对调用方很不友好。

尝试过程

查了很多关于Nacos 获取配置中心的资料,资料都很浅显,都是在一个 controller 里面获取,关于静态方法获取的资料找到篇是用 @PostConstruct 注解一个方法将变量赋值给一个 static 变量,这种方法还真行,不过缺点很明显,参数只会在进程启动的时候加载进去,配置中心修改之后并不会生效,需要重启进程才会生效,没有什么价值。

解决方案

试了很多方案都行不通,于是请教组内老司机帮忙协助,在静态方法用 SpringBeanUtil.getBean(AppConfig.class) 这个方法先实例化 bean,然后用 bean 去调用里面的动态方法,是的,获取配置里面的方法还是换成了动态的,这样才方便获取到 @Value 的值,但是用来给业务层调用的方法依然是 static,对业务层调用无影响。

Nacos 配置中心接入流程梳理

官方文档:https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html

- 阅读全文 -

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 就可以解决此问题,这就可以放心的发版了!

记一次 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

Kafka 配置外网访问

说明


Kafka 有的时候会跨机房接收消息,本地开发机也需要向远程服务器发一些消息,默认是不支持外连的,所以需要配置一下远程访问。

Kafka 服务器 host 修改

查看 hostname,查看内网 IP 并记录

cat /etc/hostname
# vm172-31-110-6.ksc.com #

ifconfig

编辑 host 文件

vim /etc/hosts
# 添加在文件底部 #
172.31.110.6 vm172-31-110-6.ksc.com

Kafka 配置文件修改

修改 server.properties 配置文件,具体目录视情况而定。

vim /opt/kafka_2.12-2.2.0/config/server.properties

# 修改 listeners #
listeners=PLAINTEXT://vm172-31-110-6.ksc.com:9092

需要留意一下 advertised.listeners 要注释掉,listeners 才会有效。

修改 zookeeper.connect 配置,如果 Zookeeper 和 Kafka 不在同一台机器,请配置 Zookeeper 地址。

zookeeper.connect=vm172-31-110-6.ksc.com:2181

客户端 host 配置

在客户端机器修改 host 文件映射到远程外网 IP,内网的 consumer 机器请配置内网 IP 映射。

xxx.xx.xx.xx  vm172-31-110-6.ksc.com