010.LNMP拆分

LNMP架构拆分

单台节点运行LNMP架构会导致网站访问缓慢,当内存不够时甚至会导致系统出现OOM(内存溢出),出现OOM时系统会随机kill掉占用系统内存最大的进程,这个进程就可能是数据库,一旦MySQL在使用过程中被kill掉,可能会导致数据库崩溃,出现无法重启服务和数据丢失的情况

模拟OOM故障

# 1.查看当前内存信息
[root@web01 ~]# free -m
[root@web01 ~]# swapoff -a		# 关闭swap,否则内存不足时会使用swap空间

# 2.根据可分配内存available数量,占用适量内存
[root@web01 ~]# dd if=/dev/zero of=/dev/null bs=770M count=1024

# 3.新开一个ssh连接,此时ssh连接已经非常缓慢
[root@web01 ~]# free -m 	# 再次查看内存使用情况,可用内存应该只有十几或二十几
[root@web01 ~]# systemctl start mariadb 	# 尝试开启数据库或其他占用内存较多的程序

# 4.回到第一个ssh连接可以看到,程序已经被系统killed
[root@web01 ~]# dd if=/dev/zero of=/dev/null bs=770M count=1024
Killed

# 5.查看系统日志记录
[root@web01 ~]# tail /var/log/messages
Feb 20 13:51:23 temp kernel: Out of memory: Kill process 2415 (dd) score 755 or sacrifice child
Feb 20 13:51:23 temp kernel: Killed process 2415 (dd), UID 0, total-vm:896588kB, anon-rss:788580kB, file-rss:0kB, shmem-rss:0kB

Nginx + PHP(编译)

此处使用LNMP编译再安装一次,使用的软件版本与yum安装的不同,所以在编译安装之前需要先卸载yum安装的软件包

1.下载软件包

[root@web01 ~]# wget http://nginx.org/download/nginx-1.22.1.tar.gz
[root@web01 ~]# wget https://www.php.net/distributions/php-8.1.16.tar.gz

2.安装nginx

# 1.编译安装nginx
[root@web01 nginx-1.22.1]# tar -xzf nginx-1.22.1.tar.gz
[root@web01 nginx-1.22.1]# cd nginx-1.22.1
[root@web01 nginx-1.22.1]# yum install -y gcc pcre-devel openssl-devel
[root@web01 nginx-1.22.1]# ./configure --prefix=/usr/local/nginx/ \
> --sbin-path=/usr/local/nginx/nginx \
> --conf-path=/usr/local/nginx/nginx.conf \
> --pid-path=/usr/local/nginx/nginx.pid \
> --with-http_ssl_module
[root@web01 nginx-1.22.1]# make && make install
[root@web01 nginx-1.22.1]# cd

# 2.使用systemd管理nginx
[root@web01 ~]# vim /usr/lib/systemd/system/nginx.service
[Unit]
Description=Nginx Server
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
Type=forking
ExecStart=/usr/local/nginx/nginx
ExecReload=/usr/local/nginx/nginx -s reload
ExecStop=/usr/local/nginx/nginx -s quit
[root@web01 ~]# systemctl daemon-reload
[root@web01 ~]# systemctl start nginx

# 3.编辑站点配置文件
[root@web01 ~]# mkdir /usr/local/nginx/conf.d
[root@web01 ~]# ln -s /usr/local/nginx/nginx /usr/bin/nginx
[root@web01 ~]# vim /usr/local/nginx/conf.d/wordpress.example.com.conf
server {
  listen 80;
  server_name wordpress.example.com;
  charset utf-8,gbk;
  root /opt/wordpress/;

  location / {
    index index.php index.html;
  }

  location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;	# 此处使用相对路径
  }
}
[root@web01 ~]# cp /usr/local/nginx/conf.d/wordpress.example.com.conf /usr/local/nginx/conf.d/wecenter.example.com.conf
[root@web01 ~]# diff /usr/local/nginx/conf.d/{wordpress.example.com.conf,wecenter.example.com.conf}
3c3
<   server_name wordpress.example.com;
---
>   server_name wecenter.example.com;
5c5
<   root /opt/wordpress/;
---
>   root /opt/wecenter/;

# 4.修正nginx授权
[root@web01 ~]# vim /usr/local/nginx/nginx.conf
user  www;
include /usr/local/nginx/conf.d/*.conf;
  # 由于编译安装的主配置文件没有上述include路径,所主配置文件本身就存在一个server块,server块内只保留error页面的配置,其他配置注释
[root@web01 ~]# chown -R www.www /usr/local/nginx
  1. 安装php
# 1.编译安装php
[root@web01 ~]# tar -xzf php-8.1.16.tar.gz
[root@web01 ~]# cd php-8.1.16/
[root@web01 php-8.1.16]# yum install -y libxml2-devel sqlite-devel
[root@web01 php-8.1.16]# ./configure --prefix=/usr/local/php/ --enable-fpm --with-mysqli
[root@web01 php-8.1.16]# make && make install
[root@web01 php-8.1.16]# cp php.ini-production /usr/local/php/lib/php.ini
    # 在不确定php.ini文件应该存放在什么路径的情况下,通过phpinfo()测试文件能够看到php默认从什么路径下读取,也可以通过php --ini命令查看
    # 如果php.ini文件存放的位置有误,也不会影响php-fpm启动,它有一个默认的配置文件

# 2.systemd管理php
[root@web01 php-8.1.16]# cp sapi/fpm/php-fpm.service /usr/lib/systemd/system/
[root@web01 php-8.1.16]# cd /usr/local/php/
[root@web01 php]# cp etc/php-fpm.conf.default etc/php-fpm.conf
[root@web01 php]# cp etc/php-fpm.d/www.conf.default etc/php-fpm.d/www.conf
[root@web01 php]# vim lib/php.ini
short_open_tag = On    # 此选项决定是否展示测试页,默认值是On,但出于安全考虑,php.ini-production文件将此选项值设置为Off
[root@web01 php]# systemctl daemon-reload 
[root@web01 php]# systemctl start php-fpm

# 3.修正php授权
[root@web01 php]# vim etc/php-fpm.d/www.conf
user = www
group = www
[root@web01 php-fpm.d]# vim /usr/lib/systemd/system/php-fpm.service
ProtectSystem=false   # 修改为false,否则启动php-fpm时会因为只读文件导致无法生成日志文件启动报错
[root@web01 php]# chown -R www.www /usr/local/php

# 3.测试PHP
[root@web01 ~]# vim /usr/local/nginx/html/index.php
<?php
  phpinfo();
?>
[root@web01 ~]# vim /usr/local/nginx/conf.d/test-php.conf
server {
  listen 80;
  server_name _;
  root /usr/local/nginx/html/;
  index index.php index.html;
  location / {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
  }
}

拆分数据库(编译)

拆分数据库能够有效缓解Web节点压力,并提高用户访问速度

  1. 备份Web01数据库

web01节点上的Mariadb是5.5版本,db01节点上的MySQL是5.7版本,直接从Mariadb5.5导出的数据到MySQL5.7可能会报错,此时可以先将web01节点的数据库升级到MySQL5.7版本再导出备份数据

# Web01节点Mariadb数据库备份
[root@web01 ~]# mysqldump -uroot -predhat --all-databases --single-transaction > mysql-all.sql
[root@web01 ~]# scp mysql-all.sql root@172.16.1.51:/root
  1. db01节点安装MySQL
# 1.准备安装环境
[root@db01 ~]# wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.26-linux-glibc2.12-x86_64.tar.gz
[root@db01 ~]# useradd -s /sbin/nologin -M mysql    # 新建系统管理用户
[root@db01 ~]# mkdir /var/lib/mysql/    # MySQL数据存放目录
[root@db01 ~]# chown -R mysql.mysql /var/lib/mysql/
[root@db01 ~]# tar -xzf mysql-5.7.26-linux-glibc2.12-x86_64.tar.gz -C /usr/local/
[root@db01 ~]# mv /usr/local/mysql-5.7.26-linux-glibc2.12-x86_64/ /usr/local/mysql
[root@db01 ~]# chown -R mysql.mysql /usr/local/mysql
[root@db01 ~]# yum remove mariadb-libs  # 卸载系统自带的mariadb包

# 2.配置MySQL
[root@db01 ~]# echo "export PATH=$PATH:/usr/local/mysql/bin/" >> /etc/profile
[root@db01 ~]# . /etc/profile     # 设置环境变量
[root@db01 ~]# mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql/ --datadir=/var/lib/mysql/  # 初始化数据库
[root@db01 ~]# vim /etc/my.cnf
[mysqld]
user=mysql
basedir=/usr/local/mysql/
datadir=/var/lib/mysql/
socket=/var/lib/mysql/mysql.sock

[mysql]
socket=/var/lib/mysql/mysql.sock

[client]
socket=/var/lib/mysql/mysql.sock

# 3.使用systemd工具管理MySQL
[root@db01 ~]# vim /usr/lib/systemd/system/mysqld.service
[Unit]
Description=MySQL Server
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf
LimitNOFILE=5000
[root@db01 ~]# systemctl daemon-reload
[root@db01 ~]# systemctl start mysqld
[root@db01 ~]# mysqladmin -uroot -p  password 'redhat'  # 修改MySQL默认密码

# 4.导入数据库
[root@db01 ~]# mysql -uroot -predhat
mysql> source /root/mysql-all.sql   # 导入数据库
mysql> flush privileges;
mysql> quit;
[root@db01 ~]# mysql_upgrade -uroot -predhat -S /var/lib/mysql/mysql.sock   # 更新表结构

编译方式安装完所有LNMP组件后,测试的方式仍与前文是一样的,建议在使用前先进行基本的LNMP的测试,因为由于编译安装基本上都是采用的使用最基本的参数进行编译,这必然会导致后续安装wordpress或wecenter时,出现缺少库文件或编译参数,导致站点无法正常运行,如果问题都集中在一起再进行排查,无疑会增加处理难度

  1. web01节点PHP重定向到db01节点数据库
# 1.db01授权MySQL远程登录
[root@db01 ~]# mysql -uroot -predhat
mysql> grant all privileges on wordpress.* to wordpress@'172.16.1.%' identified by 'redhat';
mysql> grant all privileges on wecenter.* to 'wecenter'@'172.16.1.%' identified by 'redhat';

# 2.db01测试远程连接是否正常
[root@db01 ~]# firewall-cmd --add-service=mysql --permanent
[root@db01 ~]# firewall-cmd --reload
[root@db01 ~]# setenforce 0
[root@db01 ~]# mysql -uwordpress -predhat -h 172.16.1.51

# 3.web01节点停止本地数据库服务
[root@web01 ~]# systemctl stop mariadb

# 4.web01节点修改wordpress程序的配置文件
[root@web01 ~]# vim /opt/wordpress/wp-config.php
/** Database username */
define( 'DB_USER', 'wordpress' );

/** Database hostname */
define( 'DB_HOST', '172.16.1.51' );

# 5.web01节点修改wecenter程序的配置文件
[root@web01 ~]# cd /opt/wecenter
[root@web01 wecenter]# grep -R 'redhat'     # 过滤此目录下哪些文件内容有redhat
[root@web01 wecenter]# vim ./system/config/database.php
'host' => '172.16.1.51',
'username' => 'wecenter',

某些类型的网站如果更改数据库连接后,即没有报错,首页也没有反应,可能是因为站点本身对之前的配置做了缓存,不妨清理缓存后再试试

补充:站点错误信息

  1. wordpress登录页面底部语言部分出现错误提示,原因是编译安装php时未安装zlib.so扩展,补充php的扩展即可
错误信息:
Fatal error: Uncaught Error: Call to undefined function gzinflate()

解决办法:
[root@web01 ~]# yum install -y autoconf
[root@web01 ~]# cd /root/php-8.1.16/ext/zlib    # 进入php安装包的对应扩展的目录下
[root@web01 zlib]# cp config0.m4 config.m4
[root@web01 zlib]# /usr/local/php/bin/phpize
[root@web01 zlib]# ./configure --with-php-config=/usr/local/php/bin/php-config --with-zlib
[root@web01 zlib]# make && make install
[root@web01 zlib]# ls /usr/local/php/lib/php/extensions/no-debug-non-zts-20210902/  # 验证是否存在zlib扩展
[root@web01 zlib]# vim /usr/local/php/lib/php.ini   # 修改php配置文件,使新添扩展生效
extension=zlib.so   # 添加此行,重启php

注:某些情况下,wordpress的站点并不会直接提示错误信息,而是提示网站遇到重大问题,此时需要打开网站调试模式查看具体日志信息

错误信息:There has been a critical error on your website.Please check your site admin email inbox for instructions.

解决办法:
[root@web01 ~]# vim /usr/local/nginx/html/wordpress/wp-config.php
define( 'WP_DEBUG', true);
define( 'WP_DEBUG_DISPLAY', false);
define( 'WP_DEBUG_LOG', true);  # 默认存放在wp-content目录下的debug.log文件,也可以通过单引号指定日志存放路径
  1. wordpress官方英文版软件包不包含中文语言包,也就是wp-content/languages/目录下没有任何文件,即便在wordpress站点设置语言为中文也不会产生任何变化,需要从官网下载中文语言包解压后放在wp-content/languages/目录下
官网地址:https://cn.wordpress.org/download/releases/

解决办法:
  1. php添加扩展包错误

wecenter需要的php扩展包很多,包括但不限于zlibfreetypejpeggdcurlopenssl,这些扩展又需要libjpeg-devellibpng-develfreetype-devellibcurl-developenssl-devel等系统运行库的支撑,具体需要安装的扩展和运行库,根据实际的系统环境进行修改

在php 8.1版本下安装php扩展时,有部分扩展安装过程会报错,例如pdo_mysqlcurl,根据安装的扩展不同,错误信息路径有细微差别;根据错误信息中的提示,使用选项-std=c99-std=gnu99来make编译代码。使用phpize的时候是根据系统环境生成configure文件,执行configure会生成Makefile文件,make命令依赖Makefile进行构建

错误信息:/root/php-8.1.16/ext/pdo_mysql/mysql_statement.c:57:4: note: use option -std=c99 or -std=gnu99 to compile your code
        /root/php-8.1.16/ext/pdo_mysql/mysql_statement.c: In function ‘pdo_mysql_stmt_after_execute_prepared’:
        /root/php-8.1.16/ext/pdo_mysql/mysql_statement.c:169:2: error: ‘for’ loop initial declarations are only allowed in C99 mode

解决办法:
[root@web01 ~]# cd /root/php-8.1.16/ext/pdo_mysql
[root@web01 pdo_mysql]# vim Makefile
...
CFLAGS = --std=c99 -g -O2
...

错误信息:In file included from /usr/local/php/include/php/Zend/zend.h:41:0,
                         from /root/php-8.1.16/ext/mbstring/libmbfl/mbfl/mbfilter.h:88,
                         from /root/php-8.1.16/ext/mbstring/libmbfl/filters/mbfilter_htmlent.c:31:/usr/local/php/include/php/Zend/zend_signal.h:44:2: error: unknown type name ‘siginfo_t’  siginfo_t *siginfo;

解决办法:
[root@web01 ~]# cd /root/php-8.1.16/ext/mbstring
[root@web01 ~]# cd /root/php-8.1.16/ext/mbstring
...
CFLAGS = --std=gnu99 -g -O2
...

建议:如果安装wecenter高版本的过程中出现错误,同时又无法判断问题具体处在哪里,建议将wecenter先换成低版本,低版本安装过程中会将系统环境中所缺少的组件更加详细的展现出来,补充好系统环境之后再换成高版本即可

  1. wecenter访问错误
错误信息:htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated


  1. 404响应码,日志记录/favicon.ico

/favicon.ico文件本身是指的站点的logo,这个logo通常显示在浏览器的标签页上,这个logo不是必须存在的;有些时候访问站点返回404响应码,查看日志时发现浏览器请求了/favicon.ico文件,此时不要被这个信息误导,这有可能是你的nginx配置文件有误导致的;如果不想在nginx日志中看到/favicon.ico的日志,也可以不对其进行记录日志,仅需要在同站点配置文件server下添加一个location

location /favicon.ico {
  return 200;    # 客户端请求/favicon.ico文件时返回200
  access_log off;    # 不记录/favicon.ico的日志
}

Web集群扩展

单台web节点的访问量是有限的,且存在单点故障的风险,多台web节点能够保障业务的持续稳定,并能够提升用户访问网站的速度

直接扩展web节点仍存在问题,例如,用户不知道该访问哪个web节点,某些类型的资源是存储在web节点本地的,例如图片,此时如果用户切换web节点访问网站可能会出现访问不到图片的情况

  1. 新增web02节点配置
# 1.新建虚拟机并配置主机名和IP
# 2.配置yum源
  1. 安装nginx和php

安装Web集群就应该保持所有web节点的配置相同,这其中就包括nginx和php的软件版本,web01使用yum源安装的旧版本php,web02应该也保持如此

[root@web02 ~]# yum install -y nginx php71w php71w-cli php71w-fpm php71w-mysqlnd php71w-opcache php71w-gd freetype
[root@web02 ~]# systemctl enable nginx
[root@web02 ~]# systemctl enable php-fpm
[root@web02 ~]# setenforce 0
[root@web02 ~]# firewall-cmd --add-service=http --permanent
[root@web02 ~]# firewall-cmd --reload
  1. 同步web01的配置文件
[root@web02 ~]# rsync -avz --delete root@172.16.1.7:/etc/nginx/ /etc/nginx/
[root@web02 ~]# rsync -avzP --delete root@172.16.1.7:/etc/php* /etc/
  1. 同步代码文件
[root@web02 ~]# rsync -avz --delete root@172.16.1.7:/opt/ /opt/

同步代码文件后如果配置正确,此时访问web02可以正常看到wordpress站点和wecenter站点,在wordpress站点上新建一篇文章并插入图片后,再次修改本地hosts解析站点为web01节点,再打开wordpress找到在web02节点上新建的文章可以看到,文字还在,图片无法加载出来

拆分静态资源至共享存储

当后端web节点出现多台时,势必会导致用户上传的图片、视频、附件等内容只能存放在一台web节点上,其他web节点无法访问到该资源,而NFS存储正好解决了web集群静态资源一致性的问题,实现静态资源的统一管理,便于推送CDN进行静态资源加速

  1. 配置NFS服务器

此处大部分步骤已经在NFS章节执行过了

[root@nfs ~]# yum install -y nfs-utils
[root@nfs ~]# vim /etc/exports
/opt/wordpress  172.16.1.0/24(rw,sync,all_squash,anonuid=666,anongid=666)
/opt/wecenter   172.16.1.0/24(rw,sync,all_squash,anonuid=666,anongid=666)
[root@nfs ~]# groupadd -g 666 www
[root@nfs ~]# useradd -u 666 -g 666 www
[root@nfs ~]# mkdir /opt/{wordpress,wecenter}
[root@nfs ~]# chown -R www.www /opt/{wordpress,wecenter}
[root@nfs ~]# systemctl start nfs
  1. 将图片文件推送到NFS

通过浏览器查询图片路径有2种方式,一是开启浏览器的调试模式可以找到图片路径,二是鼠标右击图片复制连接,以web02上传的图片为例,复制图片链接为http://wordpress.example.com/wp-content/uploads/2023/02/1.png,从此处就能看出图片存放在nginx根目录下的/wp-content/uploads/,nginx的根目录根据配置文件各有不同

# 1.找到图片路径

# 2. 推送图片到NFS
[root@web02 ~]# scp -rp /opt/wordpress/wp-content/uploads/* root@172.16.1.31:/opt/wordpress/
[root@nfs ~]# chown -R www.www /opt/wordpress/

上传文件到NFS节点后必须再执行一次授权更改,否则web节点无法写入新的数据

  1. web节点挂载存储
# web02节点挂载
[root@web02 ~]# yum install -y nfs-utils
[root@web02 ~]# mount -t nfs 172.16.1.31:/opt/wordpress/ /opt/wordpress/wp-content/uploads/
# web01节点挂载
[root@web01 ~]# yum install -y nfs-utils
[root@web01 ~]# mkdir /opt/wordpress/wp-content/uploads
[root@web01 ~]# mount -t nfs 172.16.1.31:/opt/wordpress/ /opt/wordpress/wp-content/uploads/

web01节点未上传过图片,没有自动生成uploads目录,手动创建后挂载nfs存储,再次刷新浏览器能够看到图片。可以通过web01节点再次上传一个新的图片,更改本地hosts解析后再访问web02节点,如果能够正常访问到web01上传的图片,说明静态资源共享成功

posted @ 2023-06-19 09:19  hebo  阅读(21)  评论(0)    收藏  举报