前言
如果已经在 LNMP 架构下工作 2-3 年时间, 这个阶段我们对自己常用的技术栈的工作原理一定需要有一个基本的认识. 一方面, 可以去学习这些优秀软件的设计思路, 另一方面, 可以为分析系统瓶颈和系统优化打好基础. 今天我们就来看看 PHP-fpm/nginx/Redis/MySQL 的进程模型.
PHP-fpm 的进程模型
PHP-fpm 采用了 master-worker 多进程的模型, 其次与 PHP-CGI 相比提供了更好的进程管理方式. PHP-fpm 的进程模型示例图如下:
master 主进程的主要任务:
监听 socket(TCP/IP 或者 Unix Domain Socket)
管理子进程
master 通过如下的信号来对进程进行管理:
SIGINT/SIGTERM 退出信号
SIGQUIT 优雅退出信号
SIGUSR1 重新加载日志文件信号
SIGUSR2 平滑重启信号
SIGCHLD 回收子进程资源信号(wait/waitpid 防止异常退出的子进程变成僵尸进程, 僵尸进程会占用 pid 等内核资源)
worker 工作进程的主要任务:
accept 请求
执行具体的 PHP 脚本
多进程 (单线程) 并发模型
nginx 的进程模型
同样, nginx 也采用了 master-worker 多进程的模型, 进程模型图如下所示:
但是与 PHP-fpm 主要的不同的是:
master 进程不负责监听端口
worker 进程自身监听端口(多个进程会产生惊群效应, nginx 使用互斥锁使同一时刻只有一个进程去 listen 端口)
master 通过如下的信号来对进程进行管理:
SIGINT/SIGTERM 退出信号
SIGQUIT 优雅退出信号
SIGHUP 平滑重启信号
SIGUSR1 重新加载日志文件信号
SIGUSR2 平滑升级信号
SIGWINCH 优雅退出某个 worker 进程信号
多进程 (单线程) 和多路 I/O 复用并发模型
Redis 的进程模型
Redis 采用的是单进程的模型, 如下图所示:
但是, Redis 需要实现持久化, 持久化的方式一般有两种 RDB(写快照)/AOF(写命令), 持久化的过程 Redis 会 fork 一个子进程来完成, 目的不阻塞 master 工作进程. 如下图所示:
单进程 (单线程) 和多路 I/O 复用并发模型
MySQL 的进程模型
MySQL 谈进程模型其实还是不合适, MySQL 主要采用的是多线程的架构.
多线程并发模型
总结
PHP-fpm 多进程, 符合 PHP 语言的设计思想「简单」. 进程间资源隔离, 简单且复杂性底, 反之相对于而言高流量下性能会不是很好.
nginx 多进程, worker 去监听端口, 一方面, 使得 master 专注于进程管理; 另一方面, 提高服务的健壮性, 如果有一个 worker 挂了别的 worker 还可以继续处理请求; 其次, 发挥计算机多核的优势.
Redis 单进程, 采用 I/O 多路复用性能已经足够的好, Redis 基本都是内存操作, 不使用多线程, 避免了大量竞争, 简化了系统的复杂度. 其次, Redis 也没涉及复杂的计算场景, 单核足够使用.
MySQL 多线程, 按照我目前的理解, 绝大多数常用的 MySQL 引擎的性能瓶颈是在于磁盘 IO, 多线程技术已经足够满足并发需求.
思考
从上面看来, 不同的系统设计, 根据它的运用场景都采用了符合它们自身需求的设计. 比如, PHP 的简单; nginx 的高可用高性能的 web server;Redis 高性能的 nosql;MySQL 大量的磁盘操作.
这些系统使用的多进程, 多线程, 协程, I/O 多路复用 (select/poll/epoll) 等技术手段都是指引我们去优化我们系统的方向, 这些优秀系统都为我们的设计思路提供了很好的案例, 去提高并发能力, 解决网路 IO, 磁盘 IO 问题. 这些都是我们现在以及未来需要去理解和消化的东西.
最后, 以上内容有理解不对的地方, 欢迎大家及时指正, 非常谢谢~
附录
常见 Linux 信号和数字映射表:
信号 | 数字 (LINUX) | 含义 |
---|---|---|
SIGKILL | 9 | force kill |
SIGINT | 2 | interrupt |
SIGQUIT | 3 | quit graceful |
SIGTERM | 15 | terminate |
SIGHUP | 1 | hang up |
SIGUSR1 | 10 | user defined |
SIGUSR2 | 12 | user defined |
来源: https://juejin.im/post/5bc36c035188255c5f54154e