内存溢出

内存溢出 一、什么是内存溢出 内存溢出(Memory Overflow / Out of Memory, OOM)指程序在申请内存时,没有足够的空间供其使用。在 PHP 中,通常表现为: 脚本超出 memory_limit 设置(默认 128M),抛出 Fatal error: Allowed memory size of X bytes exhausted 系统级 OOM:PHP 进程消耗了操作系统分配的所有内存,被内核强制杀死(常见于常驻进程如 Swoole、Workerman) 二、如何排查内存溢出? 1. 查看错误日志 PHP 错误日志中会直接记录内存耗尽的位置和当前内存使用量。 系统日志(/var/log/messages 或 journalctl -xe)可看到是否因 OOM Killer 杀死了进程。 2. 使用内存分析工具 Xdebug 的追踪功能 xdebug.profiler_enable = 1 xdebug.profiler_output_dir = /tmp 生成 cachegrind 文件,用 QCacheGrind 或 WebGrind 分析,查看哪个函数/行消耗了大量内存。 Xdebug 的垃圾回收统计 xdebug_debug_zstd('your_var'); // 显示变量内存占用(需扩展) 使用 memory_get_usage() / memory_get_peak_usage() 在代码关键位置打印内存,定位峰值点: echo memory_get_usage() . " bytes\n"; // 执行一段代码 echo memory_get_peak_usage() ....

March 28, 2025 · 2 min · Leanku

线程安全

内存溢出 PHP本身(无论是PHP-FPM还是Swoole)并不支持多线程。 线程安全,在PHP的世界里通常指以下两种情况,我们需要分开讨论: PHP解释器自身的线程安全:指PHP作为C语言编写的程序,当其被嵌入到多线程的Web服务器(如Apache的worker MPM)中时,多个线程能否安全地共用一个PHP解释器实例。 PHP应用代码的并发安全:指我们的业务代码在同时处理多个请求时,如何避免共享数据的冲突。这在Swoole这类常驻内存的进程中尤其重要。 下面分别介绍: 1. PHP解释器的线程安全(Zend线程安全,ZTS) 这是PHP源码编译时的一个选项(–enable-zts)。 问题背景:PHP有很多全局变量(例如存放已加载扩展列表的变量)。在单线程环境下没问题,但在多线程环境下,线程A修改这个全局变量时,线程B可能正在读取,导致崩溃。 解决方案(ZTS):PHP通过TSRM(线程安全资源管理器) 为每个线程分配了一个独立的“全局变量副本”。线程A修改自己的副本,不会影响线程B。 对开发者的影响: PHP-FPM(Nginx+PHP-FPM):使用的是多进程模型,一个进程只处理一个请求。进程间内存天然隔离,不存在线程安全问题,因此通常编译非线程安全(NTS) 版本,性能更高。 Apache + worker MPM:Apache使用多线程模型,此时PHP必须编译为ZTS版本才能稳定运行。 Swoole:Swoole本身是多进程模型。每个Worker进程是单线程的,事件循环和协程都在这个主线程中运行。因此,PHP的ZTS在Swoole环境下并非必需,Swoole官网也推荐使用NTS版本的PHP。 小结:对于绝大多数PHP开发者(使用PHP-FPM或Swoole),无需关心PHP底层的ZTS。你基本不会直接编写相关代码,这是扩展开发者和PHP本身需要解决的问题。 2. 应用代码的并发安全:Swoole常驻内存下的挑战 在传统的PHP-FPM中,每个请求结束后,所有变量都被销毁,下一个请求是“干净”的,所以不存在并发安全问题。 但在Swoole中,Worker进程常驻内存,多个协程或请求会并发地操作进程内的同一个全局变量、静态变量或资源(如Redis连接),这就会引发经典的竞态条件(Race Condition)。 典型问题场景: // 一个 Worker 进程内的全局计数器 $globalCounter = 0; // 协程A 和 协程B 同时执行这段代码 $globalCounter++; // 这不是原子操作! echo $globalCounter; 两个协程同时读取0,分别加1,然后写回。你期望输出2,但实际可能输出1。这就是并发问题。 如何保证Swoole下的并发安全? Swoole提供了几种机制来解决这个问题: 方案一:使用原子计数器(Atomic) Swoole提供的Swoole\Atomic是一个基于CPU原子操作的计数器,操作是线程/协程安全的。 $atomic = new Swoole\Atomic(0); // 在任意协程中安全地增加 $atomic->add(); // 无锁,高性能 echo $atomic->get(); 方案二:使用锁(Lock) 对于复杂的共享数据读写(不只是计数),可以使用各种锁。 协程锁(Swoole\Lock 或 Channel):推荐,只在协程级别阻塞。 $lock = new Swoole\Lock(Swoole\Lock::SPIN); // 自旋锁 $lock->lock(); // ....

March 28, 2025 · 1 min · Leanku

PHP + Redis秒杀场景

PHP + Redis秒杀场景 在电商秒杀等高并发场景中,Redis 凭借其内存操作和原子性特性,成为库存扣减的核心组件。 下面以 PHP + Redis 为例,给出一个企业级秒杀库存设计方案示例,重点解决超卖、热点 Key、重复下单和流量冲击等问题。 一、核心思路 预加载库存:秒杀活动开始前,将商品库存从 MySQL 同步到 Redis(使用 SET 或 HMSET)。 原子扣减:使用 Redis Lua 脚本(或 DECR + 校验)保证扣减与校验的原子性,杜绝超卖。 异步落库:扣减成功后,将用户 ID、商品 ID 推入消息队列(如 Redis Stream / List),后台进程消费并创建订单、扣减数据库库存。 限流 + 防重:通过令牌桶或滑动窗口限制用户访问频率,通过 Redis 记录用户抢购状态防止同一用户重复下单。 二、详细步骤与代码实现 1. 活动开始前:初始化库存 // 假设商品ID=1001,秒杀库存=100 $redis->set('seckill:stock:1001', 100); $redis->set('seckill:closed:1001', 0); // 0-未结束,1-已结束 2. 抢购接口核心:Lua 脚本原子扣减 $lua = <<<LUA local stock_key = KEYS[1] local user_key = KEYS[2] -- 用于记录已抢购用户 local user_id = ARGV[1] local closed_key = KEYS[3] -- 检查活动是否已结束 if redis....

March 28, 2025 · 4 min · Leanku

Mysql窗口函数

Mysql窗口函数 一、什么是窗口函数? 窗口函数是一种在查询结果的"窗口"上执行计算的函数,它不会像常规聚合函数那样将多行合并为一行,而是为每一行返回一个值,同时保持原始行数不变。 基本语法 <窗口函数>(<参数>) OVER ( [PARTITION BY <分区表达式>] [ORDER BY <排序表达式> [ASC | DESC]] [ROWS/RANGE <窗口范围>] ) ‌<窗口函数>‌:可以是聚合函数(如SUM、AVG)或专用函数(如ROW_NUMBER、RANK)。‌‌ ‌OVER()‌:必需子句,定义窗口框架。‌‌ ‌PARTITION BY‌:可选,用于分组数据;若省略,窗口覆盖整个结果集。 ‌ORDER BY‌:可选,指定窗口内行的排序顺序。‌‌ ‌窗口范围‌:可选,默认ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。‌‌ 二、 准备测试数据 -- 创建销售数据表 CREATE TABLE sales ( sale_id INT PRIMARY KEY, salesperson VARCHAR(50), region VARCHAR(50), sale_date DATE, amount DECIMAL(10,2) ); INSERT INTO sales VALUES (1, '张三', '北京', '2023-01-15', 5000), (2, '李四', '上海', '2023-01-16', 8000), (3, '王五', '北京', '2023-01-17', 6000), (4, '张三', '北京', '2023-02-01', 7000), (5, '李四', '上海', '2023-02-02', 9000), (6, '赵六', '广州', '2023-02-03', 4000), (7, '王五', '北京', '2023-02-04', 5500), (8, '张三', '北京', '2023-03-01', 8500); -- 创建员工薪资表 CREATE TABLE employee_salary ( emp_id INT, name VARCHAR(50), department VARCHAR(50), salary DECIMAL(10,2), hire_date DATE ); INSERT INTO employee_salary VALUES (1, '张三', '技术部', 15000, '2020-01-15'), (2, '李四', '技术部', 12000, '2021-03-20'), (3, '王五', '销售部', 8000, '2022-06-10'), (4, '赵六', '销售部', 7500, '2022-08-05'), (5, '钱七', '技术部', 13000, '2020-11-30'), (6, '孙八', '人事部', 9000, '2021-09-15'), (7, '周九', '技术部', 16000, '2019-05-20'); 1....

February 20, 2025 · 4 min · Leanku

MyCat实现Mysql分库分表

Mysql分库分表和主从复制 MyCat 实现分库分表 MySQL 的分库分表解决方案通常依赖于中间件来实现水平扩展。常见的中间件有以下几种 MyCat ShardingSphere TDDL (Taobao Distributed Data Layer) Cobar Vitess MyCat 是一款开源的数据库中间件,支持 MySQL 数据库的分库分表功能。 使用 MyCat 实现分库分表的过程包括多个步骤,涉及配置 MyCat 和数据库的分片策略,路由规则等。下面通过一个实际案例来详细解释 MyCat 的实现原理、方式和步骤。 案例背景 假设你有一个电商系统,包含一个 orders 表,记录用户的订单信息。随着数据量的增长,单一数据库难以满足性能需求,因此需要进行 分库分表。 实现原理 MyCat 是一种数据库中间件,支持分库分表。它的原理是通过代理 MySQL 连接,将 SQL 请求转发到实际的数据库实例上。MyCat 会根据预定义的路由规则(如分片策略)来决定将查询请求路由到哪个数据库或表。 MyCat 的 分库分表原理如下: 分库:将数据按照某种规则分配到多个数据库实例中。例如,按用户的 ID 来分库。 分表:将一个大表拆分成多个小表,避免单表的数据过大导致查询性能下降。例如,可以按时间范围或数据量来分表。 实现方式 MyCat 的实现方式主要通过 配置分片规则 来实现分库分表。配置内容包括: 数据源配置:定义数据库实例。 分片规则配置:指定哪些字段用于分片,如何分片(按范围、按哈希等)。 路由规则配置:根据 SQL 查询的条件来路由请求到不同的数据库或表。 实现步骤 安装并启动 MyCat 下载 MyCat 安装包并解压。 配置 MyCat 启动脚本,启动 MyCat。 cd MyCat ./bin/start.sh 配置数据源 在 MyCat 的配置文件 conf/context....

February 18, 2025 · 3 min · Leanku

Linux grep命令

Linux grep命令 全拼:Global search REgular expression and Print out the line. 作用:文本搜索工具,根据用户指定的“模式(过滤条件)”对目标文本逐行进行匹配检查,打印匹配到的行. 模式:由正则表达式的元字符及文本字符所编写出的过滤条件﹔ grep的语法格式: grep -option(参数) ‘word’(关键词) file(文本文件); grep常用参数: –color=auto 或者 –color:表示对匹配到的文本着色显示 -i:在搜索的时候忽略大小写 -n:显示结果所在行号 -c:统计匹配到的行数,注意,是匹配到的总行数,不是匹配到的次数 -o:只显示符合条件的字符串,但是不整行显示,每个符合条件的字符串单独显示一行 -v:输出不带关键字的行(反向查询,反向匹配) -w:匹配整个单词,如果是字符串中包含这个单词,则不作匹配 -Ax:在输出的时候包含结果所在行之后的指定行数,这里指之后的x行,A:after -Bx:在输出的时候包含结果所在行之前的指定行数,这里指之前的x行,B:before -Cx:在输出的时候包含结果所在行之前和之后的指定行数,这里指之前和之后的x行,C:context -e:实现多个选项的匹配,逻辑or关系 -q:静默模式,不输出任何信息,当我们只关心有没有匹配到,却不关心匹配到什么内容时,我们可以使用此命令,然后,使用”echo $?”查看是否匹配到,0表示匹配到,1表示没有匹配到。 -P:表示使用兼容perl的正则引擎。 -E:使用扩展正则表达式,而不是基本正则表达式,在使用”-E”选项时,相当于使用egrep。 示例 # 从test.txt文本文件中搜索包含”L”字符的行 grep "L" test.txt # 输出以 I 开头的行(不区分大小写) grep "^i" test.txt -i -n -o # 可以使用”--color”选项,高亮显示行中的关键字 grep "L" test.txt -i -n --color # -B”选项,显示符合条件的行之前的行,"B"有before之意 grep "L" test.txt -i -n --color -B2 # "-A"有After之意,"-A"代表显示符合条件的行的同时,还要显示之后的行,"-A3"表示同时显示符合条件的行之后的3行。 grep "L" test....

February 17, 2025 · 2 min · Leanku

Linux sed命令

Linux sed命令 全拼:Stream EDitor(流编辑器) Linux sed 命令是利用脚本来处理文本文件,sed 可依照脚本的指令来处理、编辑文本文件。Sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。 sed 的运行模式 当处理数据时,Sed 从输入源一次读入一行,并将它保存到所谓的模式空间pattern space中。所有 Sed 的变换都发生在模式空间。变换都是由命令行上或外部 Sed 脚本文件提供的单字母命令来描述的。大多数 Sed 命令都可以由一个地址或一个地址范围作为前导来限制它们的作用范围。 sed的相关选项 -n, –quiet, –silent 取消自动打印模式空间 -e 脚本, –expression=脚本 添加“脚本”到程序的运行列表 -f 脚本文件, –file=脚本文件 添加“脚本文件”到程序的运行列表 –follow-symlinks 直接修改文件时跟随软链接 -i[扩展名], –in-place[=扩展名] 直接修改文件(如果指定扩展名就备份文件) -l N, –line-length=N 指定“l”命令的换行期望长度 –posix 关闭所有 GNU 扩展 -r, –regexp-extended 在脚本中使用扩展正则表达式 -s, –separate 将输入文件视为各个独立的文件而不是一个长的连续输入 -u, –unbuffered 从输入文件读取最少的数据,更频繁的刷新输出 –help 打印帮助并退出 –version 输出版本信息并退出 -a ∶新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~ -c ∶取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行! -d ∶删除,因为是删除啊,所以 d 后面通常不接任何咚咚;...

February 17, 2025 · 1 min · Leanku

Linux 进程管理命令

Linux ps命令 ps 命令是 Process Status 的缩写,是一个命令行实用程序,用于显示或查看与Linux系统中运行的进程相关的信息。 命令原理:ps 是通过读取虚拟文件:/proc 拿到进程数据的,不需要给 ps 设置任何的权限就可以运行。 在Linux中,每个进程都有多个ID来关联它,包括: Process ID (PID),即进程ID 这是标识进程的任意数字。每个进程都有一个唯一的ID,但是在进程退出并且父进程检索了退出状态之后,进程ID将被释放,供新进程重用。 Parent Process ID (PPID),即父进程ID 如果父进程在子进程退出之前退出,则子进程的PPID将更改为另一个进程。 Process Group ID (PGID) 这是进程组leader的PID。如果PID == PGID,则此进程是进程组领导。 Session ID (SID) 这是会话领导者的PID。如果PID == SID,则此进程为会话领导进程。 会话和进程组只是将一些相关的进程作为一个单元来对待的方法。一个进程组的所有成员总是属于同一个会话,但是一个会话可以有多个进程组。 通常,shell将是会话领导者,该shell执行的每个管道将是一个进程组。这是为了在shell退出时很容易杀死它的子进程。 grep -option(参数) ‘word’(关键词) file(文本文件); ps命令选项: 简单筛选 a :选择所有进程(BSD-Style)。 -A :选择所有进程,与 -e 等同(标准格式)。 -a :选择除 session 领导者和没有与终端关联的进程之外的所有进程。 -d :选择除了 session leader 的所有进程。 –deselect :选择除满足指定条件之外的所有进程,即反选,与 -N 等同。 -e :选择所有进程,与 -A 等同。 -N :与 –deselect 等同。...

February 17, 2025 · 3 min · Leanku

视频内容处理工具分享之 VideoLingo

视频内容处理工具分享之 VideoLingo VideoLingo 是目前处理视频技术内容最强的开源工具之一。它的核心优势在于不仅仅是“语音转文字”,它还会利用 AI(如 DeepSeek 或 GPT)对内容进行 NLP 断句(让文字像书一样好读)并生成总结。 一、安装方式: 1. 最简单“一键整合包”(适合 Windows 用户) 如果你不想折腾 Python 环境,可以寻找社区维护的一键整合包(如 GitHub 上的 VideoLingo-OneClick 项目)。 下载:从网盘或 GitHub Releases 下载解压包。 启动:双击 启动软件.exe 或 一键启动.bat。 配置:它会弹出一个网页界面。在左侧填入你的 LLM API Key(支持 DeepSeek、OpenAI 等,技术总结必须用到大模型)。 2. 标准安装 如果你想体验最新功能,建议通过源码安装: 1. 准备环境 安装 Python 3.10(必须是这个版本)。 安装 FFmpeg(参考上一个回答)。 如果你有 NVIDIA 显卡,建议安装 CUDA Toolkit 12.6 以获得加速。 2. 源码下载与安装 在终端(Terminal/CMD)中执行: # 1. 克隆项目 git clone https://github.com/Huanshere/VideoLingo.git cd VideoLingo # 2. 安装依赖(需要 python=3.10 建议使用 conda) conda create -n videolingo python=3....

January 11, 2025 · 2 min · Leanku

视频下载工具分享之 yt-dlp

视频下载工具分享之 yt-dlp yt-dlp 是一个功能强大的开源命令行视频下载工具,它本身不需要像常规软件那样运行安装程序。 一、安装方式: 1. Windows 用户(最简单方法) 下载 exe 文件:前往 yt-dlp GitHub 释放页,找到并下载 yt-dlp.exe。 创建文件夹:建议在 C 盘或 D 盘根目录创建一个文件夹(如 D:\ytdlp),将下载好的 .exe 放进去。 安装 FFmpeg (重要依赖):为了能下载高画质视频并自动合并音视频,你必须下载 FFmpeg。 在同一目录下放入 ffmpeg.exe。 添加到 PATH (可选但建议):将该文件夹路径添加到系统的“环境变量”中,这样你就可以在任何地方的终端直接输入 yt-dlp 使用它了。 2. macOS 用户 推荐使用 Homebrew 快速安装: 打开终端(Terminal),输入: brew install yt-dlp ffmpeg 3. Linux 用户 大多数发行版可以直接通过包管理器安装: Ubuntu/Debian: sudo apt install yt-dlp Arch Linux: sudo pacman -S yt-dlp 或者直接下载二进制文件: sudo wget https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -O /usr/local/bin/yt-dlp sudo chmod a+rx /usr/local/bin/yt-dlp 4....

January 10, 2025 · 1 min · Leanku