作者: ethan

  • linux 极限内存优化记录

    前言

    因为用来开发的机器,内存实在太小,经常触发oom导致执行php脚本非常慢且经常被killed掉,所以,痛定思痛,进行一下极限内存优化。

    注: 以下步骤仅限于非生产环境。

    查看占用内存进程

    top(然后按下M,注意大写)

    处理

    php-cgi数量优化

    修改 php-fpm.conf, 重启php-fpm

    pm = ondemand

    pm.start_servers = 1

    减少mysql内存占用

    在/etc/my.cnf配置中,增加以下配置, 重启mysql

    #检测的表对象的最大数目

    performance_schema_max_table_instances=400

    #表定义缓存中表的个数

    table_definition_cache=400

    #表文件描述符的缓存大小

    table_open_cache=256

    减少nginx进程数

    在nginx.conf配置中, 减少worker_processes数,重启nginx

    worker_processes:1

  • php大数据量导出csv

    工作中,经常用到需要将大量数据导出的场景,而大数据量的导出,csv比之excel速度更快,文件更小,更满足需求。

    以下是一个csv文件导出类,综合考虑了系统内存,文件格式等各类问题

    class Csv
    
    {
    
        private static $_instance = NULL;
    
        private static $_pointer = null;
    
        private function __construct()
    
    {
    
    }
    
        public static function getInstance() {
    
            if (is_null(self::$_instance)) {
    
                self::$_instance = new Csv();
    
            }
    
            return self::$_instance;
    
        }
    
        private function __clone()
    
    {
    
            // TODO: Implement __clone() method.
    
        }
    
        public static function initCsv($filename, $head) {
    
            ob_clean();
    
            header('Content-type: text/csv; charset=UTF-8');
    
            header('Content-Disposition: attachment; filename="' . $filename . '.csv"'); //指定下载文件的描述
    
            header("Content-Type: application/force-download");
    
            // 添加bom头,避免excel打开文件乱码
    
            $bom  = pack("H*", 'EFBBBF');
    
            self::$_pointer  = fopen("php://output", "w");
    
            fwrite(self::$_pointer, $bom);
    
            fputcsv(self::$_pointer, $head);
    
        }
    
        public static function makeCsvByStep($items) {
    
            foreach ($items as $item) {
    
                // 长数字处理
    
                foreach ($item as &$val) {
    
                    $val = "\t" . $val;
    
                }
    
                fputcsv(self::$_pointer, $item);
    
                ob_flush();
    
                flush();
    
            }
    
    }
    
        public static function exportCsv() {
    
            fclose(self::$_pointer);
    
            exit;
    
        }
    
    }
  • docker mysql 占内存过多

    解决docker部署mysql后,mysql占用内存过多的问题

    查看内存占用

    docker stats

    更改配置

    在/etc/my.cnf配置中,增加以下配置(ps: 建议将/etc/my.cnf挂载在宿主机已目录)

    #检测的表对象的最大数目
    
    performance_schema_max_table_instances=400
    
    #表定义缓存中表的个数
    
    table_definition_cache=400
    
    #表文件描述符的缓存大小
    
    table_open_cache=256

    重启mysql容器

    docker restart mysql
  • centos7 docker部署

    前言

    Docker 要求 CentOS系统的内核版本高于 3.10, 通过 uname -r 命令查看你当前的内核版本

    安装

    yum update -y
    yum -y install docker

    若要安装最新版本,可执行

    curl -fsSL https://get.docker.com/ | sh
    systemctl start docker

    ps:若安装过程出现以下类似错误,是因为系统的python版本升级导致.

    找到对应的文件,如/usr/bin/yum

    所有的python版本一般在/usr/bin/目录下,也可用whereis python查看

    配置国内镜像源

    ps:docker安装好后默认没有此文件,需要手动创建,添加阿里云镜像节点,并指定docker存储目录

    vim /etc/docker/daemon.json
    {
    
    "registry-mirrors" :[
    
        "http://ovfftd6p.mirror.aliyuncs.com",
    
        "http://registry.docker-cn.com",
    
        "http://docker.mirrors.ustc.edu.cn",
    
        "http://hub-mirror.c.163.com"
    
    ],
    
        "insecure-registries" : [
    
            "registry.docker-cn.com",
    
            "docker.mirrors.ustc.edu.cn"
    
    ]
    
    }

    启动docker,并加入开机启动

    systemctl start docker
    systemctl enable docker

    测试

    下载hello-world镜像

    docker pull hello-world

    运行hello-world镜像

    docker run hello-world
  • docker 部署python,gunicorn,flask

    python容器部署

    1. 下载镜像 下载镜像地址 我们此处下载

    docker pull python:3.9.21

    2. 容器部署

    docker run --restart always -itd -p 9081:9081 --name python-3.9.21 -v /Users/ethanxu/Docker/www/htdocs:/go --privileged=true python:3.9.21
    # 说明
    --name python-3.9.21 : 把容器命名为python-3.9.21
    -itd: i 以交互模式运行容器 txa0 为容器重新分配一个伪输入终端 d 后台运行容器,并返回容器ID 注意如果不加上it的话她或运行Python容器后自动关闭
    -v /data/www/htdocs/:/www :将主机中/data/www/htdocs/目录挂载到容器的/www

    3. 测试 在/data/www/htdocs目录下新建hello.py文件,内容为

    #!/usr/bin/python
    
    print("Hello World!")

    4. 在终端输入

    docker exec -it python python /www/hello.py

    flask应用部署

    1. 创建自定义网络

    docker network create --subnet=172.18.0.0/16 mynetwork

    2. 删除原python镜像, 创建新对象

    docker rm -f python
    docker run --net mynetwork --ip 172.18.0.5 -p 8000:8000 --name python -itd -v /data/www/htdocs/:/www python

    3. 安装扩展

    在/data/www/htdocs目录下新建requirements.txt文件

    flask
    
    gunicorn
    
    gevent
    
    markdown
    
    flask_bootstrap

    如果你要安装其他拓展的话在requirements.txt文件中添加相关插件即可(注意一个插件换一行)

    在终端输入如下命令进行安装:

    # 使用国内镜像https://pypi.tuna.tsinghua.edu.cn/simple
    docker exec -it python pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r /www/requirements.txt

    4. gunicorn配置

    在/data/www/htdocs目录下新建gunicorn.conf.py文件

    # 并行工作进程数
    
    workers = 4
    
    # 指定每个工作者的线程数
    
    threads = 2
    
    # 监听内网端口8000
    
    bind = '0.0.0.0:8000'
    
    # 设置守护进程,将进程交给supervisor管理
    
    daemon = 'true'
    
    # 工作模式协程
    
    worker_class = 'gevent'
    
    # 设置最大并发量
    
    worker_connections = 2000
    
    # 设置进程文件目录
    
    pidfile = '/var/run/gunicorn.pid'
    
    # 设置访问日志和错误信息日志路径
    
    accesslog = '/var/log/gunicorn_acess.log'
    
    errorlog = '/var/log/gunicorn_error.log'
    
    # 设置日志记录水平
    
    loglevel = 'warning'

    5. 增加gunicorn启动文件

    在/data/www/htdocs目录下新建gunicorn.py文件

    import os
    
    import sys
    
    def start():
    
        cmd = 'cd /www/eblog; gunicorn -c gunicorn.conf.py eblog:app'
    
        os.system(cmd)
    
    def stop():
    
        cmd = "ps -ef | grep '/usr/local/bin/gunicorn' | awk '{print $2}' | xargs kill -9 > /dev/null 2>&1"
    
        os.system(cmd)
    
    def restart():
    
        stop()
    
        start()
    
    if sys.argv[1] == 'start':
    
        start()
    
    elif sys.argv[1] == 'restart':
    
        restart()
    
    elif sys.argv[1] == 'stop':
    
        stop()
    
    else:
    
        print('params error!')

    6. 启动gunicorn

    docker exec -i python python /www/gunicorn.py start
  • 随笔

    静静的,

    闭着眼躺在阳台椅子上,

    徜徉在天空之城的音符下,

    抚慰着这一天的琐碎嘈杂,

    静谧,

    无扰,

    空明,

    愿岁月无逝,

    此刻永恒。

  • 芸芸众生

    人流如潮风云过,

    岁月如刀斩天骄!

  • php7与php5底层区别

    1. 抽象语法树

    php7之前的版本,直接将php代码在语法解析阶段生成ZendVM指令, 编译器和执行器是耦合在一起的,所以如果语法规则或执行引擎有一个变,则另外一个也要跟着改变才可以。

    php7增加了抽象语法树,首先将php代码解析生成抽象语法树,然后将抽象语法树编译为ZendVm指令,将php的编译器与执行器很好的隔离开.

    2. Native TLS

    php7之前的版本,为了线程安全,不能够使用全局变量,只能通过传参的形式实现函数间的资源共享。

    php7使用Native TLS(线程局部存储)来保存线程的资源池,简单的说,就是通过__thread表示一个全局变量,这样这个全局变量就是线程独享的了。

    3. 指定函数参数、返回值类型

    e,g,

    function foo(string $name): array {

    return [];

    }

    4. zval结构的变化

    php7将引用计数(refcount_gc)转移到了具体的value中,避免复制变量时需要复制两个结构,使php变量之间的复制、传递更加简洁、易懂,zval结构的大小也从24byte减少到了16byte,这是php7能够境地系统资源占用的一个优化点所在.

    5. 异常处理

    php7将多数错误改为了异常抛出 Throwable

    6. HashTable的变化

    HashTable结构的大小从72byte减小到了56byte, 数组元素Bucket结构也从72byte减小到了32byte

    7. 执行器

    执行器的调度函数为execute_ex(), 这个函数负责执行php代码编译生成的ZendVM执行.

    执行期间会频繁的用到execute_data、opline两个变量,之前版本中,这两个变量是由execute_ex()通过参数传递给各指令handler的,php7改为用寄存器存储这两个变量,避免了传参导致的频繁的出入栈操作,同时寄存器访问速度更快,这个优化使得php的性能有了5%左右的提升

    8. 新的参数解析形式

  • 醒红尘

    无由生厌心彷徨,

    伫立四望悲凄凉。

    遥想少年风华茂,

    书生意气志飞扬。

    激扬文字斥方遒,

    指点江山傲王侯。

    经年易逝经年了,

    尘世如刀斩天骄。

    红尘如流未经歇,

    怎可奈何随波去。

    此刻鱼跃思前尘,

    终归无奈逐流逝。

    唯期缥缈龙门现,

    或可化龙游九天。

  • 人生际遇

    际遇无由祸福依,

    前途陌路条丝缕。

    或行或顾风尘历,

    可叹前路或有期。