linux参数调优之swoole

连接数优化、系统内核调优

ulimit -n 文件最大打开数 单个进程能支持最大的 fd 取决于 ulimit -n 的值 参考资料

net.ipv4.tcp_mem  =   379008       505344  758016 
net.ipv4.tcp_wmem = 4096        16384   4194304
net.ipv4.tcp_rmem = 4096          87380   4194304
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

sysctl -a 查看全部参数
sysctl -N [参数] 参数是否存在
sysctl -n [参数] 查看参数的值
sysctl -w arg=value # -w arg=value arg表示内核参数,value表示设置值。给内核参数临时设置一个值

net.ipv4.tcp_mem

#确定 TCP 栈应该如何反映内存使用;每个值的单位都是内存页(通常是 4KB)
#第一个值是内存使用的下限
#第二个值是内存压力模式开始对缓冲区使用应用压力的上限
#第三个值是内存上限。在这个层次上可以将报文丢弃,从而减少对内存的使用。对于较大的 BDP 可以增大这些值(但是要记住,其单位是内存页,而不是字节)

net.ipv4.tcp_rmem

#与 tcp_wmem 类似,不过它表示的是为自动调优所使用的接收缓冲区的值

net.ipv4.tcp_wmem = 30000000 30000000 30000000

#为自动调优定义每个 socket 使用的内存。
#第一个值是为 socket 的发送缓冲区分配的最少字节数
#第二个值是默认值(该值会被 wmem_default 覆盖),缓冲区在系统负载不重的情况下可以增长到这个值
#第三个值是发送缓冲区空间的最大字节数(该值会被 wmem_max 覆盖)

net.core.wmem_default = 11059200

#定义默认的发送窗口大小;对于更大的 BDP 来说,这个大小也应该更大

net.core.rmem_default = 10000000

#指定了接收套接字缓冲区大小的缺省值(以字节为单位)

net.core.rmem_max = 10000000

#指定了接收套接字缓冲区大小的最大值(以字节为单位)

net.core.wmem_max = 11059200

#定义发送窗口的最大大小;对于更大的 BDP 来说,这个大小也应该更大

net.ipv4.tcp_tw_reuse 在Ubuntu中这个参数值是0(r73)

是否socket reuse,此函数的作用是Server重启时可以快速重新使用监听的端口。如果没有设置此参数,会导致server重启时发生端口未及时释放而启动失败
表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭

net.ipv4.tcp_tw_recycle 在Ubuntu中没有发现这个参数(r73)

使用socket快速回收,短连接Server需要开启此参数。此参数表示开启TCP连接中TIME-WAIT sockets的快速回收,Linux系统中默认为0,表示关闭。打开此参数可能会造成NAT用户连接不稳定,请谨慎测试后再开启。
表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭

相关资料

内核参数调整之swoole
内核参数调整之easy-swoole
TCP/IP及内核参数优化调优
linux系统怎么查看及设置内核参数

tcp_tw_reuse、tcp_tw_recycle 使用场景及注意事项

es-docker

FROM php:7.2

# Version
ENV PHPREDIS_VERSION 4.0.1
ENV SWOOLE_VERSION 4.4.4
ENV EASYSWOOLE_VERSION 3.x-dev

# Timezone
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo 'Asia/Shanghai' > /etc/timezone

# Libs
RUN apt-get update \
    && apt-get install -y \
    curl \
    wget \
    git \
    zip \
    libz-dev \
    libssl-dev \
    libnghttp2-dev \
    libpcre3-dev \
    && apt-get clean \
    && apt-get autoremove -y

# Composer
RUN curl -sS https://getcomposer.org/installer | php \
    && mv composer.phar /usr/local/bin/composer \
    && composer self-update --clean-backups

# PDO extension
RUN docker-php-ext-install pdo_mysql

# Bcmath extension
RUN docker-php-ext-install bcmath

# Redis extension
RUN wget http://pecl.php.net/get/redis-${PHPREDIS_VERSION}.tgz -O /tmp/redis.tar.tgz \
    && pecl install /tmp/redis.tar.tgz \
    && rm -rf /tmp/redis.tar.tgz \
    && docker-php-ext-enable redis

# Swoole extension
RUN wget https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz -O swoole.tar.gz \
    && mkdir -p swoole \
    && tar -xf swoole.tar.gz -C swoole --strip-components=1 \
    && rm swoole.tar.gz \
    && ( \
    cd swoole \
    && phpize \
    && ./configure --enable-async-redis --enable-mysqlnd --enable-openssl --enable-http2 \
    && make -j$(nproc) \
    && make install \
    ) \
    && rm -r swoole \
    && docker-php-ext-enable swoole


# 部署node-agent
ADD swoole-tracker-vx.y.z.tar.gz /tmp/
RUN cp /tmp/86d89a960330704760/swoole_tracker72.so /usr/local/lib/php/extensions/no-debug-non-zts-20170718/ && \
    cd /tmp/86d89a960330704760 && \
    ./deploy_env.sh 192.168.56.102 && \
    rm -rf /tmp/86d89a960330704760

# 添加entrypoint脚本
RUN printf '#!/bin/sh\n/opt/swoole/script/php/swoole_php /opt/swoole/node-agent/src/node.php &\nphp $@' > /opt/swoole/entrypoint.sh && \
    chmod 755 /opt/swoole/entrypoint.sh

# 启用entrypoint脚本(-x方便调试, 可以去掉)
# ENTRYPOINT [ "sh", "-x", "/opt/swoole/entrypoint.sh" ]

RUN printf 'extension=/usr/local/lib/php/extensions/no-debug-non-zts-20170718/swoole_tracker72.so\n' > /usr/local/etc/php/conf.d/swoole-tracker.ini


WORKDIR /var/www/code



# Install easyswoole
RUN cd /var/www/code \
    && composer require easyswoole/easyswoole=${EASYSWOOLE_VERSION} \
    && php vendor/bin/easyswoole install

EXPOSE 9501

ENTRYPOINT ["php", "/var/www/code/easyswoole", "start"]
FROM centos:centos7

#version defined
ENV SWOOLE_VERSION 4.4.4
ENV EASYSWOOLE_VERSION 3.x-dev

#update core
RUN yum update -y

#install libs
RUN yum install -y curl zip unzip  wget openssl-devel gcc-c++ make autoconf

#install php
RUN yum install -y epel-release
RUN rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
RUN yum clean all
RUN yum update -y
RUN yum install -y php71w-devel php71w-openssl php71w-gd php71w-mbstring php71w-mysqli

# composer
RUN curl -sS https://getcomposer.org/installer | php \
    && mv composer.phar /usr/bin/composer \
    && composer self-update --clean-backups

# use aliyun composer
RUN composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

# swoole ext
RUN wget https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz -O swoole.tar.gz \
    && mkdir -p swoole \
    && tar -xf swoole.tar.gz -C swoole --strip-components=1 \
    && rm swoole.tar.gz \
    && ( \
    cd swoole \
    && phpize \
    && ./configure --enable-openssl \
    && make \
    && make install \
    ) \
    && sed -i "2i extension=swoole.so" /etc/php.ini \
    && rm -r swoole

# Dir
WORKDIR /easyswoole

# install easyswoole

RUN cd /easyswoole \
    && composer require easyswoole/easyswoole=${EASYSWOOLE_VERSION} \
    && php vendor/bin/easyswoole install


# 部署node-agent
ADD swoole-tracker-vx.y.z.tar.gz /tmp/
RUN cp /tmp/86d89a960330704760/swoole_tracker71.so /usr/lib64/php/modules/ && \
    cd /tmp/86d89a960330704760 && \
    ./deploy_env.sh 192.168.56.102 && \
    rm -rf /tmp/86d89a960330704760

# 添加entrypoint脚本
RUN printf '#!/bin/sh\n/opt/swoole/script/php/swoole_php /opt/swoole/node-agent/src/node.php &\nphp-fpm $@' > /opt/swoole/entrypoint.sh && \
    chmod 755 /opt/swoole/entrypoint.sh

# 启用entrypoint脚本(-x方便调试, 可以去掉)
ENTRYPOINT [ "sh", "-x", "/opt/swoole/entrypoint.sh" ]

RUN printf 'extension=/usr/lib64/php/modules/swoole_tracker71.so\n' > /etc/php.d/swoole-tracker.ini


EXPOSE 9501

easyswoole中的mysqli带条件返回数据及总条数

easyswoole mysqli 分页

正确用法

<?php
$table_name = 'xsk_test';
$page=3;
$page_size=20;
$db->where('status', 1);
$db->withTotalCount();
$data = $db->get($table_name,[($page-1)*$page_size,$page_size],'*');
$count = $db->getTotalCount();

错误用法

<?php
$table_name = 'xsk_test';
$page=3;
$page_size=20;
$db->where('status', 1);
$data = $db->get($table_name,[($page-1)*$page_size,$page_size],'*');
$count = $db->count();// 这儿的count的where条件会消失

mysqli的源码

count是再次调用了get的方法 源码位置

    /**
     * 聚合-计算总数
     * @param string $tableName 表名称
     * @param string|null $filedName 字段名称
     * @return mixed
     * @throws ConnectFail
     * @throws PrepareQueryFail
     */
    public function count($tableName, $filedName = null)
    {
        if (is_null($filedName)) {
            $filedName = '*';
        }
        $isFetch = $this->isFetchSql;
        $retval = $this->get($tableName, null, "COUNT({$filedName}) as retval");
        if ($isFetch || $retval instanceof Mysqli) {
            return $retval;
        }
        return $retval ? $retval[0]['retval'] : false;
    }

相关资料

官方文档

php-单元测试

easyswoole 单元测试 php单元测试

安装

composer require easyswoole/phpunit Tip: 自3.2.5版本的Easyswoole起,已经默认集成了 easyswoole/phpunit 组件

目录结构

|--App
|--|--|
.....
|--Tests
|--|--Api
|--|--|--IndexTests.php
|--|--Models
|--|--|--UserTests.php

IndexTests.php API接口测试

<?php


namespace Tests\Api;
use PHPUnit\Framework\TestCase;
use App\HttpController\Index;
use EasySwoole\HttpClient\HttpClient;

class IndexTests extends TestCase
{
    protected $baseUrl = 'http://ip地址:9501';

    public function testIndex()
    {
        $url = $this->baseUrl . '/user/login'; 
        $client = new HttpClient($url);


        $username = 'zhangshan';
        $password = 'qwe12345';
        $deviceId = 1;

        $client->setQuery(['username' => $username, 'password' => $password, 'device_type' => $deviceId]);

        $response = $client->get();

        $body = $this->parsingJson($response->getBody());

        if ($response->getBody()) {
            var_dump($body);
        } else {
            echo 'Error: ' . $response->getErrCode() . ': ' . $response->getErrMsg() . "\n";
        }

        $this->assertTrue(true);//断言结果是否为true,如果不为true则报错
        $this->assertEquals('hello world', $response->response);//断言结果是否等于hello world,如果不等于则报错
    }
    /**
     * 解析json数据
     *
     * @param string $jsonStr
     * @return object
     */
    protected function parsingJson($jsonStr)
    {
        // $body = json_decode($jsonStr);
        return json_decode($jsonStr);
    }
}

UserTests.php 数据模型测试

<?php
namespace Tests\Models;
use PHPUnit\Framework\TestCase;
use App\Models\AccountModel;

class UserTests extends TestCase
{
    public function testInfo()
    {
        $uid = 13;
        $accountModel = new AccountModel();
        $data=  $accountModel->info($uid);
        // var_dump($data); 8
        $this->assertEquals(8, $data['robot_id']);//断言返回的id为1
    }
}

相关资料

phpunit-单元测试神器
Easyswoole/Phpunit

APP支付SDK-支付宝-PHP

调试支付宝一直出现-ALIN10146-系统繁忙

出现的问题: ALIN10146-系统繁忙

  • 错误1: 由于在创建应用的使用选择了[公钥证书]加签方式、(PHP不要选择这一项、这个一旦确定就不可以修改了、只能重新创建提交审核)
  • 错误2: 参数加的位置错误
// 使用easyswoole集成的composer包-错误使用方式
        $aliConfig = new \EasySwoole\Pay\AliPay\Config();
        $aliConfig->setGateWay(\EasySwoole\Pay\AliPay\GateWay::NORMAL);
        $aliConfig->setAppId('2019091167181387');
        $aliConfig->setPublicKey('xxxxxx');
        $aliConfig->setPrivateKey('xxxxxxxx');
        $pay = new \EasySwoole\Pay\Pay();
        $order = new \EasySwoole\Pay\AliPay\RequestBean\App();
        $order->setSubject($orderDesc);
        $order->setOutTradeNo($orderSn);
        $order->setTotalAmount($money);
        $aliPay = $pay->aliPay($aliConfig);
        $result = $aliPay->app($order)->toArray();
        $result ['notify_url'] = 'http://261843m3y6.wicp.vip:52034/ali/pay_notify'; # 这个回调通知地址不可以加到这儿、可有可无
        foreach ($result as &$value) {
            $value = $this->characet($value, $result['charset']);
        }
        $body ['body'] = http_build_query($result);
        return $body;
// 使用easyswoole集成的composer包-正确使用方式
        $aliConfig = new \EasySwoole\Pay\AliPay\Config();
        $aliConfig->setGateWay(\EasySwoole\Pay\AliPay\GateWay::NORMAL);
        $aliConfig->setAppId('2019091167181387');
        $aliConfig->setPublicKey('xxxxxx');
        $aliConfig->setPrivateKey('xxxxxxxx');
        $aliConfig->setNotifyUrl('http://261843m3y6.wicp.vip:52034/ali/pay_notify'); # 需要的话通过这个方法添加
        $pay = new \EasySwoole\Pay\Pay();
        $order = new \EasySwoole\Pay\AliPay\RequestBean\App();
        $order->setSubject($orderDesc);
        $order->setOutTradeNo($orderSn);
        $order->setTotalAmount($money);
        $aliPay = $pay->aliPay($aliConfig);
        $result = $aliPay->app($order)->toArray();
        foreach ($result as &$value) {
            $value = $this->characet($value, $result['charset']);
        }
        $body ['body'] = http_build_query($result);
        return $body;

支付结果验签

// 使用easyswoole集成的composer包
        $param = $this->request()->getRequestParam();
        unset($param['sign_type']);
        $aliConfig = $this->aliPayConfig();
        $aliConfig->setPublicKey('支付宝公钥(当你生成公钥填入到支付宝开发平台、平台会生成一个公钥-共两个公钥)'); # 支付的时候用自己的公钥、验签用支付宝公钥
        $order = new \EasySwoole\Pay\AliPay\RequestBean\NotifyRequest($param,true);
        $pay = new \EasySwoole\Pay\Pay();
        $aliPay = $pay->aliPay($aliConfig);
        if($aliPay->verify($order)) {

沙箱配置

RSA(SHA1)密钥 和 RSA2(SHA256)密钥(推荐) 两个只要填写一个即可, RSA指得是工具中的1024, RSA2指得是工具生成的2048

应用网关: 指得是支付宝服务推送消息接收地址(我们自己服务器中的地址外网可访问的)

授权回调地址: 用于需要用户授权的处理的回调地址

阿里开发平台-APP应用添加

注意: 加签管理中-选择公钥(不要选择公钥证书-官方SDK没有提供PHP对证书的加签方式 需要自己实现-JAVA的官方SDK提供了)

秘钥生成工具

注意: 要选择PKCS1(非JAVA使用)

相关资料

调用接口-时序图 下拉到: 第四步:调用接口
请求参数
PHP服务端 SDK 生成 APP支付订单信息示例

生成 RSA 密钥
联调日志排查
沙箱调试 需要登录后-开发中心-开发服务-研发服务

ALIN10146-系统繁忙

支付宝接口错误代码 invalid-signature 错误原因: 验签出错
支付宝报错:系统繁忙,请稍后再试

遇到调试不同可以点击、有技术点我、图标然后输入”人工客服”

swoole开启openssl

安装swoole扩展两种方式1. pecl 2. 编译安装

环境说明

  • 宿机win10
  • 操作主机vbox-ubuntu
  • 安装主机docker [letsdockerize/laradock-php-fpm:2.4-7.2]

pecl方式安装

pecl install swoole-4.4.4

执行上面命令后待定一段时间后、会出现下面询问对话输入[y]就是开启, 但是在dockerfile中无法自动为其输入[y]. 方法未找到. dockerfile可以使用编译方式安装.

...
381 source files, building
running: phpize
Configuring for:
PHP Api Version:         20170718
Zend Module Api No:      20170718
Zend Extension Api No:   320170718
enable sockets supports? [no] : 
enable openssl support? [no] : 
enable http2 support? [no] : 
enable mysqlnd support? [no] : 
building in /tmp/pear/temp/pear-build-defaultusernDqLij/swoole-4.4.1
....

编译安装

    curl -o /tmp/swoole.tar.gz https://github.com/swoole/swoole-src/archive/v4.4.1.tar.gz -L && \
    tar zxvf /tmp/swoole.tar.gz && cd swoole-src* && \
    phpize && \
    ./configure \
    --enable-openssl  \
    --enable-http2  \
    --enable-async-redis \
    --enable-mysqlnd && \
    make && make install && \
    docker-php-ext-enable swoole

查看swoole扩展信息

php –ri swoole

出现openssl字符说明已启用openssl

root@4c5bf38c1a5d:/var/www/html# php --ri swoole

swoole

Swoole => enabled
Author => Swoole Team <team@swoole.com>
Version => 4.4.1
Built => Sep  6 2019 05:54:34
coroutine => enabled
epoll => enabled
eventfd => enabled
signalfd => enabled
cpu_affinity => enabled
spinlock => enabled
rwlock => enabled
openssl => OpenSSL 1.1.0j  20 Nov 2018
http2 => enabled
zlib => enabled
mutex_timedlock => enabled
pthread_barrier => enabled
futex => enabled
mysqlnd => enabled
async_redis => enabled

Directive => Local Value => Master Value
swoole.enable_coroutine => On => On
swoole.enable_library => On => On
swoole.enable_preemptive_scheduler => Off => Off
swoole.display_errors => On => On
swoole.use_shortname => On => On
swoole.unixsock_buffer_size => 8388608 => 8388608

pecl install 参数选择 pecl help install

Options:
  -f, --force
        will overwrite newer installed packages
  -l, --loose
        do not check for recommended dependency version
  -n, --nodeps
        ignore dependencies, install anyway
  -r, --register-only
        do not install files, only register the package as installed
  -s, --soft
        soft install, fail silently, or upgrade if already installed
  -B, --nobuild
        don't build C extensions
  -Z, --nocompress
        request uncompressed files when downloading
  -R DIR, --installroot=DIR
        root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM
  -P DIR, --packagingroot=DIR
        root directory used when packaging files, like RPM packaging
  --ignore-errors
        force install even if there were errors
  -a, --alldeps
        install all required and optional dependencies
  -o, --onlyreqdeps
        install all required dependencies
  -O, --offline
        do not attempt to download any urls or contact channels
  -p, --pretend
        Only list the packages that would be downloaded

相关资料

pecl-swoole
github-swoole-tag
pecl 安装swoole怎么开启openssl | 如果是 Nginx 代理到 Swoole,那么 Swoole 不需要配置 SSL 编译Swoole时指定–enable-openssl或–with-openssl-dir可以开启SSL

expect – 自动交互脚本 待研究

websocket-nginx反向代理

nginx反向代理easyswoole的http和websocket

server {
    root /var/www/es;
    server_name esapi.test;
    # 代理http
    location / {
        proxy_http_version 1.1;
        proxy_set_header Connection "keep-alive";
        proxy_set_header X-Real-IP $remote_addr;
        if (!-f $request_filename) {
             proxy_pass http://192.168.3.67:9501;
        }
        # 代理websocket就靠下面两行
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection upgrade;
    }
}

相关资料

官方文档参考

长连接使用前需解决的问题

长连接、swoole、easyswoole

  • 部署安装
  • websocket、socket、mqtt服务部署及联调
  • 不同协议中的交互 硬件使用mqtt、APP使用socket
  • 每次传输的数据如何转入到对应的逻辑方法处理(http中每个URL可以对应到指定的方法)
  • 传输数据可用的数据类型有几种(二进制、json)
  • 连接认证、数据加密
  • 多进程、多线程、协程
  • 分布式部署

easyswoole

官方安装文档

安装部分

本次使用的docker安装部署、官方已给出dockerfile、但注释了 Install easyswoole下面的三行、在build的时候先不安装

build好后启动并进入镜像安装easyswoole. composer require easyswoole/easyswoole=3.x-dev

{
    # composer require  的时候不会出现下面autoload部分需要自己添加后执行 composer dumpautoload 更新命名空间映射
    "autoload": {
        "psr-4": {
            "App\\": "App/"
        }
    },
    "require": {
        "easyswoole/easyswoole": "3.x-dev"
    }
}

如果出现下面代码、并检查路径及文件名都正确的话在检查composer.json中autoload空间映射是否正确.

[Uncaught Error: Class 'App\WebSocket\WebSocketParser' not found in /var/www/code/EasySwooleEvent.php:37

websocket服务调试

websocket部署测试-官方例子

服务端使用官方文档例子, websocket客户端使用 在线调试

{"action":"hello","content":"easyswoole"} 发送的json字符串, 如果json字符不规范可以f12打开Console然后使用JSON.stringify({action: 'hello', content: 'easyswoole'})

手动部署

swoole 部署错误

需手动安装包: composer require easyswoole/socket