LNMP环境
这里首先简单的了解一下LNMP指的是什么?L是指Linux系统提供环境,N是由Nginx提供web服务,M是指MySQL数据库,P是指PHP或Python语言解析文件
前言
随着业务量日益激增,简单的LNMP环境已经无法满足业务需求,必须要对服务架构再作升级,以便应对高并发高负载的业务。
下面是自己简单做的一个部署图,主要用到了Haproxy+keepalive组合的负载均衡集群;Nginx+PHP的网页服务;后端用到的是Java有关的应用,包括Elastisearch,RabbitMQ等服务;MySQL数据库+MyCat采用主从同步和读写分离;搭建NFS服务则是因为MySQL只能保存结构型数据,为了能够更好的将网页呈现给广大用户,非结构型的数据保存在NFS集群上;Zabbix监控系统对服务集群的资源消耗进行全面监控。

LNMP环境搭建
Nginx+PHP集群搭建
1.源码安装Nginx
#官网下载长期稳定版本
wget https://nginx.org/download/nginx-1.28.0.tar.gz
#解压缩包
tar -xf nginx-1.28.0.tar.gz
#安装必要软件,其中gcc提供C语言
yum -y install make gcc pcre-devel openssl-devel
#开始编译安装
cd nginx-1.28.0
./configure --prefix=/usr/local/nginx --with-stream --with-http_stub_status_module
make&&make install
#启动nginx
/usr/local/nginx/sbin/nginx
#如果没有返回结果,请按步骤重新开始
ss -anplut | grep nginx
2.设置PHP解析
vim /usr/local/nginx/conf/nginx.conf
#定位到“location ~ \.php$”位置
#修改前
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
#修改后
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf; #这里用到的是PHP FastCGI进程管理器
}
#保存退出
3.安装PHP-FPM
yum -y install php-fpm
#检查php-fpm配置文件listen的值
sed -n '/^listen =/p' /etc/php-fpm.d/www.conf
#这里发现结果是这样的
listen = /run/php-fpm/www.sock
#修改成nginx配置监听的端口
sed -ir '/^listen =/s/= .*/= 127.0.0.1:9000/' /etc/php-fpm.d/www.conf
#重启php-fpm服务
systemctl restart php-fpm
#检查端口9000是否被监听
ss -anplut | grep :9000
4.nginx工作目录
将程序资源放入/usr/local/nginx/html,设置权限chown -R apache:apache /usr/local/nginx/html,以便php-fpm程序能够访问
MySQL服务搭建
1.MySQL安装
"""web集群也需要安装MySQL服务"""
#php-mysqlnd提供PHP与MySQL数据库的连接和交互功能
#如果业务需求特别,需要额外安装包,比如php-json,php-curl,php-xml
yum -y install mysql mysql-server php-mysqlnd
#创建数据库和用户并设置用户权限
mysql
create databases <database> charater set utf8mb4;
create user <username>@'%' identified by '<password>';
grant all on <database>.* to <username>@'%';
fulsh privilege;
exit
#验证
mysql -u<username> -p<password>
#登录失败,请重新mysql进入创建或修改密码
2.数据备份
#web集群的数据库备份
mysqldump <database> > backup.sql
#同步到MySQL服务集群中
rsync -av backup.sql 192.xx.xx.xx:/root
#导入数据包
mysql < backup.sql
3.业务文件设置
根据开发人员的要求,设置好数据库服务器地址的指向,开始登录
进阶部分
NFS服务搭建
1.安装NFS
#Web集群和NFS集群都需要安装
#记住/usr/local/nginx/html/下哪个目录是存放图片视频等非结构化数据
yum -y install nfs-utils
#NFS集群
echo "/webdata_Unstructured 192.xx.xx.xx/24(rw,no_root_squash)" > /etc/exports
#Web集群
vim /etc/fstab
....
192.xxx.xxx.xx:/webdata_Unstructured /usr/local/nginx/html/webdata_Unstructured nfs defaults 0 0
2.打包HTML文件
"""web服务打包传送"""
#打包Web服务的html文件
tar -Pcf html.tar /usr/local/nginx/html
#传送给NFS服务器
rsync -ax html.tar /webdata_Unstructured
"""NFS服务解包"""
tar -xf /webdata_Unstructured/html.tar
代理服务器搭建
1.配置haproxy
"""proxy集群"""
#安装haproxy
yum -y install haproxy
#修改haproxy配置文件/etc/haproxy/haproxy.cfg
vim /etc/haproxy/haproxy.cfg
...
#删除64行及64行后所有的文字
#添加以下内容,将<upstream_name>写成自己的集群名,<host_name>写成主机域名,前提是/etc/hosts有记录
listen <upstream_name>
bind 0.0.0.0:80
balance roundroin
server <host_name> 192.168.xx.xx.xx:80 check inter 2000 rise 2 fall 5
server <host_name> 192.168.xx.xx.xx:80 check inter 2000 rise 2 fall 5
....
#开启健康检查,非必要,<path>为访问路径,随意
listen <state>
bind 0.0.0.0:10086 #建议端口往高数字设置,切记不要占用其他程序主要端口
stats refresh 30s
stats url/<path>
stats auth admin:admin
2.中间件keepalived
master节点
"""proxy集群master节点"""
#安装keepalived
yum -y install keepalived
#修改配置
vim /etc/keepalived/keepalived.cfg
#定位global_defs{}
#内部添加
router_id <proxy_name>
vrrp_iptables
#定位vrrp_instance VI_1 {}
#内部修改
state MASTER
priority 100
#定位virtual_ipaddress {}
#内容修改为虚拟ip
192.168.xx.xx.xx
#后面全部删除
"""proxy集群backup节点"""
#定位global_defs{}添加内容与master节点一样
#定位vrrp_instance VI_1 {}
#内部修改
state BACKUP
priority 50
#定位virtual_ipaddress {}修改内容与master节点一样
MySQL数据库优化
1.主从同步
master数据库
"""master数据库"""
vim /etc/my.cnf.d/mysql-server.cnf
...
#定位[mysqld]下添加内容,数字任意
server_id=100
#保存
#进入数据库,创建用户,<replicate_nuser>自定义用户即可
create user <replicate_user>@'%' identified by '<password>';
#授权
grant replication slave no *.* to <replicate_user>;
#在8.0本版的MySQL是默认开启binglog日志
#查看日志
mysql> show master status;
+---------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| binlog.000001 | 665 | | | |
+---------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
#这里要记住File和Position的值,待会设置slave数据库要用到
slave
"""slave数据库"""
vim /etc/my.cnf.d/mysql-server.cnf
...
#定位[mysqld]下添加内容,数字任意,但是不要一样
server_id=50
#保存退出
#进入mysql
change master to
master_host="<host_address>",
master_port=3306,
master_user="<replicate_user>",
master_password="<password>",
master_log_file="binlog.000001",
master_log_pos=665;
#开启
start slave;
#检查
show slave status\G
#定位到下面位置,查看结果是否为yes
...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
#如果成功请无视下面
#失败重新开始,请先关闭slave,清除slave,再重新开始
stop slave;
reset slave all;
2.读写分离
MySQL需要中间件才可以实现读写分离,这里需要安装MyCat2,如果MySQL版本是5.0的,则安装MyCat就可以了,由于官网无法进入,可能需要用到一些手段才可以,比如VPN技术;或者用其他的中间件替代,比如Atlas,ProxySQL等。
这里有其他博主的文章以及安装过程,可以从这位博主的文章获取
修改MyCat配置文件
#修改配置文件,该配置文件主要是用于代理,这里将username和password改一下,自定义
/usr/local/mycat/conf/users/root.user.json
#修改前
{
"dialect":"mysql",
"ip":null,
"password":"123456",
"transactionType":"proxy",
"username":"root"
}
#修改后
{
"dialect":"mysql",
"ip":null,
"password":"mycat",
"transactionType":"proxy",
"username":"mycat"
}
#出现了^M不要惊讶,这是因为在windows系统编写保存到Linux系统里面
#区别是windows系统的"\r\n",而Linux是"\n"
#可以安装dos2unix对配置文件转换Linux的格式
vim /usr/local/mycat/conf/datasources/prototypeDs.data
#对user和password进行修改,不要root
{^M
"dbType":"mysql",^M
"idleTimeout":60000,^M
"initSqls":[],^M
"initSqlsGetConnection":true,^M
"instanceType":"READ_WRITE",^M
"maxCon":1000,^M
"maxConnectTimeout":3000,^M
"maxRetryCount":5,^M
"minCon":1,^M
"name":"prototypeDs",^M
"password":"123456",^M
"type":"JDBC",^M
"url":"jdbc:mysql://localhost:3306/mysql?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8",^M
"user":"root",^M
"weight":0^M
}
~
#在MyCat2服务器进入MySQL数据库,<mycat_user>作为共用用户
mysql
create user <mycat_user>@'%' identified by '<mycat_user_password>';
grant all on *.* to <mycat_user>@'%';
#启动MyCat2服务
/usr/local/mycat/bin/mycat start
#检查是否起服务
ss -anplut | grep 8066
#结果如下
tcp LISTEN 0 128 *:8066 *:* users:(("java",pid=12290,fd=71))
#再次进入MySQL服务
mysql -h127.0.0.1 -P8066 -umycat -pmycat
#如果进入失败,请检查/usr/local/mycat/conf/users/root.user.json 里面的用户和密码
#继续上一步,配置读写分离
#<master_host_address>为只写数据库,且为matser节点数据库
#<mycat_user_password>为配置文件/usr/local/mycat/conf/datasources/prototypeDs.datasource.json里面的用户
#<wirte_host>输入写操作主机的ip地址
/*+ mycat:createdatasource{
"name":"<wirte_host>",
"url":"jdbc:mysql://<master_host_address>:3306/",
"user":"<mycat_user>",
"password":"<mycat_user_password>"*/;
#<wirte_host>输入读操作主机的ip地址
/*+ mycat:createdatasource{
"name":"<read_host>",
"url":"jdbc:mysql://<master_host_address>:3306/",
"user":"<mycat_user>",
"password":"<mycat_user_password>"*/;
#检查
/*+ mycat:showdatasources{}*/\G
#如果出错,请删除:/*+ mycat:dropdatasource{"name":"<xxx>"};重新输入
MySQL创建用户
"""MySQL主服务器"""
#创建用户,用户和密码必须和mycat创建的用户一样
create user <mycat_user>@'%' identified by '<mycat_user_password>';
grant all on *.* to <mycat_user>@'%';
"""MySQL从服务器"""
#由于配置了主从同步,这里只要检查用户是否存在就可以了
select user,host from mysql.user where user="<mycat_user>";
MyCat创建集群
#输入
/*! mycat:createclusters{
"name":"<cluster_name>",
"masters":["<wirte_host>"],
"replicas":["<read_host>"]*/;
#吐槽,创建集群是最特殊的,别的都是/*+...*/,而集群是/*!...*/
#检查集群
/*+ mycat: showclusters{}*/\G
读写分离分工
"""对写操作限制"""
#进入vim /usr/local/mycat/conf/datasources/<write_host>.datasource.json
#定位修改
#修改前
"instanceType":"READ_WRITE",
#修改后
"instanceType":"WRITE",
#保存退出
"""对读操作限制"""
#进入vim /usr/local/mycat/conf/datasources/<read_host>.datasource.json
#定位修改
#修改前
"instanceType":"READ_WRITE",
#修改后
"instanceType":"READ",
#保存退出
---修改策略---
#进入/usr/local/mycat/conf/clusters/<cluster_name>.cluster.json
#定位修改
#修改前
"readBalanceType":"BALANCE_ALL",
#修改后,将访问全部分配给读的主机
"readBalanceType":"BALANCE_ALL_READ",
#保存退出
#重启mycat
/usr/local/mycat/bin/mycat restart
逻辑库添加集群
#任意创建数据库
create database school;
quit
#编辑逻辑库
vim /usr/local/mycat/conf/schemas/school.schema.json
{
"customTables":{},
"globalTables":{},
"normalProcedures":{},
"normalTables":{},
"schemaName":"school",
"targetName":"<cluster_name>" #此处添加集群即可
"shardingTables":{},
"views":{}
}
#保存退出
#重启mycat服务,至此读写分离完成
#检测读写分离
#关闭主MySQL,插入数据,会发现报错,报错信息如下
ERROR:
Communications link failure
#关闭从MySQL,查看数据,同样报错,报错信息同上
这里由于本人能力有限,每次创建数据库生成的逻辑库文件都要添加一次集群,特别麻烦,可以用脚本控制
监控系统搭建
Zabbix系统搭建需要对众多集群进行监控检测,如果在部署图上全面展开,可能影响观感,这边就单独拎出来,大概讲一下监控的架构以及部署流程。
这里采用的zabbix代理收集服务器资源信息,汇总到zabbix服务,同时设置主动监控规则,向符合规则的服务自动发送监控请求,做到自动化部署,自动化监控的工作。
报警机制则是采用两种方式,一种是短信通知,也可以是邮件通知;另一种是制作脚本,通过钉钉通知,当然了,飞书也可以。

1.安装Zabbix-server
直接进入国内Zabbix官网,页面直接选择第一个,推荐选择6.0版本的,7.0版本的可能因为服务的版本不支持使用。在选择zabbix服务平台,根据自身使用的操作系统版本选择,最后在WEB SERVER那一处选择Nginx,不要选择Apache。不知道自己版本的用cat /etc/os-release查看


往下划动,就有安装步骤,直接复制粘贴。红框的是数据还原,就将有关Zabbix的数据导入数据,数据还原时,界面会出现静止,即使按下任意键也是没有任何反应,这是正常现象,这段导入的时间很长,估计也有十来分钟请耐心等待,导入后请继续按官方页面的步骤进行后续操作安装。zabbix服务本身不需要安装Nginx,我们只要对Zabbix服务集群跟着官网操作就可以了

安装完之后开始访问web页面,官网给出的端口是8080,直接访问ip地址:端口即可,在登陆页面输入用户和密码就可以了,初始化的默认用户和密码分别是Admin和zabbix。

成功之后点击下一步,要注意的地方是,需要输入zabbix用户以及密码,时区选择Asia/Shanghai



设置好之后就就可以看到这个界面了,而这只是刚开始而已

2.安装zabbix-agent
被监控对象需要安装zabbix-gant,才能被zabbix-server采集数据。官网这里选择红框里面的Agent,步骤也是划下去直接复制粘贴就可以完事了

3.创建模板
点击配置----点击模板--点击创建模板,Group主机群组自定义。根据我们的web集群,代理集群以及MySQL集群的特性,分别选择模板


Web 集群:Template App HTTP Service/Nginx by Zabbix agent

高可用集群:Templates/Applications/HAProxy by Zabbix agent

MySQL集群:Templates/Databases/MySQL by Zabbix agent

4.设置自动发现
进入zabbix的web页面,根据图片指示点击

创建自动发现规则,修改多处,第一处是修改IP范围,也就是自动发现的IP范围,根据配置的集群ip来配;第二处是将1h修改成2m或1m都可以,时间不能太长;第三处是添加检查条件,选择SSH;后面选择IP address即可;Name自定义都可以了


创建完之后就是要让规则生效,设置发现动作;自定义Name,点击Add,将value输入我们的IP范围,确认即可


先别着急退出,点击上方的操作,再点添加,添加主机群组,也就是我们创建模板的自定义群组,添加完之后再退出就可以了

5.设置主动监控
在zabbix-agent主机上,也就是对被监控主机集群修改配置文件
vim /etc/zabbix/zabbix_agentd.conf
#定位
StartAgents=0 #开启
ServerActive=<zabbix-server_ip address>
RefreshActiveCheck=120
#保存退出
#重启服务
systemctl restart zabbix-agent
6.自动报警
人是不可能24小时盯着电脑看的,所以需要自动报警机制。先创建脚本,这里可以让AI帮忙生成脚本使用
"""飞书报警脚本"""
vim /usr/lib/zabbix/alertscripts/zabbix_alert_feishu.py
#!/usr/bin/env python3
import requests
import json
import sys
# 飞书群机器人的 webhook 地址
webhook_url = "https://open.feishu.cn/open-apis/bot/v2/hook/your_feishu_bot_webhook"
def send_feishu_alert(subject, message):
headers = {"Content-Type": "application/json"}
payload = {
"msg_type": "text",
"content": f"{subject}\n{message}"
}
response = requests.post(webhook_url, headers=headers, data=json.dumps(payload))
if response.status_code != 200:
print(f"Failed to send alert to Feishu. Status code: {response.status_code}")
else:
print("Alert sent to Feishu successfully.")
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: %s <subject> <message>" % sys.argv[0])
sys.exit(1)
subject = sys.argv[1]
message = sys.argv[2]
send_feishu_alert(subject, message)
#保存并赋予执行权限 chmod a+x /usr/lib/zabbix/alertscripts/zabbix_alert_feishu.py
"""钉钉报警脚本"""
vim /usr/lib/zabbix/alertscripts/zabbix_alert_dingding.py
#!/usr/bin/env python3
import requests
import json
import sys
import hmac
import hashlib
import base64
import urllib.parse
import time
# 钉钉群机器人的 webhook 地址和签名密钥
webhook_url = "https://oapi.dingtalk.com/robot/send?access_token=your_dingding_bot_access_token"
secret = "your_dingding_bot_secret"
def send_dingding_alert(subject, message):
timestamp = str(round(time.time() * 1000))
secret_enc = secret.encode('utf-8')
string_to_sign = f"{timestamp}\n{secret}"
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
headers = {"Content-Type": "application/json"}
payload = {
"msgtype": "text",
"text": {
"content": f"{subject}\n{message}"
}
}
full_url = f"{webhook_url}×tamp={timestamp}&sign={sign}"
response = requests.post(full_url, headers=headers, data=json.dumps(payload))
if response.status_code != 200:
print(f"Failed to send alert to Dingding. Status code: {response.status_code}")
else:
print("Alert sent to Dingding successfully.")
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: %s <subject> <message>" % sys.argv[0])
sys.exit(1)
subject = sys.argv[1]
message = sys.argv[2]
send_dingding_alert(subject, message)
#保存并赋予执行权限 chmod a+x /usr/lib/zabbix/alertscripts/zabbix_alert_dingding.py
开始创建报警媒介,在 "脚本" 栏中分别填写 /path/to/zabbix_alert_feishu.py "{ALERT.SUBJECT}" "{ALERT.MESSAGE}" 和 /path/to/zabbix_alert_dingding.py "{ALERT.SUBJECT}" "{ALERT.MESSAGE}",填写完之后再点击上方的Message templates添加信息模板就可以了



为用户添加报警媒介,也就是确认哪些有关工作人员能够收到才行,按图顺序点击,添加报警机制,我们只要注重 Average,High和Disaster级别就可以了,Send to可以随意填写,因为我们的脚本用到了飞书/钉钉的地址。添加完之后就点击更新即可。


自我总结
优点
在LNMP环境系统框架中添加Haproxy高可用代理集群,一方面是可以保持会话,让用户能够在会话期间获得连续性的服务体验,无需在多个服务进行同步会话,降低复杂性。有关NFS集群,作为数据存储和共享,能够减轻web集群的存储压力,也能够保证在负载均衡算法中让用户访问的页面完全一致。MySQL数据库优化主要针对频繁的业务往来,比如搜索,定位,注册等等,配置主从同步和读写分离,一方面是做到数据备份安全,另一方面是减轻主服务器的压力过载问题,而且主服务器如果因为某种原因宕机,从服务还可以替代主服务器使用,保证业务的流畅。zabbix监控系统是作为监视各个集群的潜在问题以及性能瓶颈的守护者,保证做到及时发现并自动报警,为业务系统的健康发展保驾护航。
缺点
传统的LNMP环境相当于一个框架,在很多的开发维护方面往往比这个更加复杂,技术更加丰富,像是前言提到的后端应用,其实还是不够的。本篇当中只是针对少量服务器进行部署配置,而实际情况中,更多的是上百台服务需要进行部署配置。集群搭建更多的使用到Ansible自动化批量部署配置启服务,这就需要我们熟悉掌握Ansible自动化运维的技术。同时考虑成本问题,是否可以用Docker容器技术制作服务?答案是可以的,这样可以节约不少成本。关于如何用容器起服务,这又要涉及更多的技术。
如果觉得不错的话可以支持一下,如果本篇内容有什么错误或纰漏,欢迎评论区指正

590

被折叠的 条评论
为什么被折叠?



