瑞吉外卖优化02-主从复制+Nginx
本笔记源自黑马程序员的视频课程——《瑞吉外卖》,总结了课程笔记、相关知识点以及可能遇到的问题解决方案,并且增加了课程中未实现的功能,供读者参考。笔记全面且条理清晰,希望帮助读者学习和理解这个外卖项目。
本项目全部笔记见:外卖项目笔记合集
1. 读写分离
问题说明
以两台数据库为例:
读写分离,降低单台数据库的访问压力。
1.1 MySQL主从复制
1.1.1 介绍
MySQL主从复制是一个异步的复制过程,底层是基于Mysql数据库自带的二进制日志功能。就是一台或多台MySQL数据库(slave,即从库)从另一台MySQL数据库(master,即主库)进行日志的复制然后再解析日志并应用到自身,最终实现从库的数据和主库的数据保持一致。MySQL主从复制是MySQL数据库自带功能,无需借助第三方工具。
MySQL复制过程分成三步:
- master将改变记录到二进制日志(binary log)
- slave将master的binary log拷贝到它的中继日志(relay log)
- slave重做中继日志中的事件,将改变应用到自己的数据库中
1.1.2 配置-前置条件
提前准备好两台服务器,分别安装Mysql并启动服务、用navicat连接上。
登录mysql:mysql -u root -p
navicat连接方法:
- 打开navicat,新建连接(Connection - mySQL),连接名任意,主机或IP地址填虚拟机端的IP地址196.168.xxx.xxx,用户名root,密码xxx。
- 将虚拟机端端口3306开放,
firewall-cmd --zone=public --add-port=3306/tcp --permanent
以及firewall-cmd --reload
。 - 在navicat双击新建的连接,即可连接上。
1.1.3 配置-主库Master
第一步:修改Mysql数据库的配置文件 vim /etc/my.cnf
1 | [mysqld] |
第二步:重启Mysql服务
systemctl restart mysqld
第三步:登录Mysql数据库mysql -uroot -p
,执行下面SQL
GRANT REPLICATION SLAVE ON *.* to 'xiaoming'@'%' identified by 'Root@123456';
上面SQL的作用是创建一个用户xiaoming,密码为Root@123456,并且给xiaoming用户授予REPLICATION SLAVE权限。常用于建立复制时所需要用到的用户权限,也就是slave必须被master授权具有该权限的用户,才能通过该用户复制。
注:MySQL8不能使用上面的一句SQL,需要先创建用户再授权,如下:
1、CREATE USER 'xiaoming' IDENTIFIED BY 'Root@123456';
2、GRANT REPLICATION SLAVE ON *.* TO 'xiaoming'@'%';
3、FLUSH PRIVILEGES;
第四步:执行SQL show master status;
,记录File和Position的值
注:上面SQL的作用是查看Master的状态,执行完此SQL后,不要再执行任何操作
1.1.4 配置-从库Slave
第一步:修改Mysql数据库的配置文件,也是 vim /etc/my.cnf
1 | [mysqld] |
第二步:重启Mysql服务
systemctl restart mysqld
第三步:登录Mysql数据库 mysql -uroot -p
,执行下面SQL
1 | change master to |
master_host是主库ip;master_user是刚才创建的用户名;master_password是刚才创建的用户密码;master_log_file是主库执行show master status;
之后显示的文件名;master_log_pos是显示的位置。
第四步:登录Mysql数据库,执行下面SQL,查看从数据库的状态show slave status;
注意这两项(分别对应Slave_IO_Running 和 Slave_SQL_Running)应该都是yes。如果不是,需要改auto.cnf,见克隆虚拟机 第7条。
1.2 读写分离案例
1.2.1 背景
面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈。对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说,将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。
1.2.2 Sharing-JDBC介绍
Sharding-JDBC定位为轻量级Java框架,在Java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
使用Sharding-JDBC可以在程序中轻松的实现数据库读写分离。
- 适用于任何基于JDBC的ORM框架,如: JPA,Hibernate,Mybatis,Spring JDBC Template或直接使用JDBC。
- 支持任何第三方的数据库连接池,如:DBCP,C3PO,BoneCP,Druid,HikariCP等。
- 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。
1.2.3 入门案例
准备工作:
1、实现主从复制(1.1节)
2、在主库创建rw数据库,从库也能看到该数据库。在rw数据库中新建数据表user。
使用Sharding-JDBC实现读写分离步骤:
1、导入maven坐标
1 | <dependency> |
2、在配置文件中配置读写分离规则
1 | spring: |
3、在配置文件中配置允许bean定义覆盖配置项
1 | spring: |
后创建的dataSource会覆盖先创建的dataSource,则不会冲突。
1.3 项目实现读写分离
1.3.1 环境准备(主从复制)
直接使用我们前面在虚拟机中搭建的主从复制的数据库环境即可。
在主库中,创建瑞吉外卖项目的业务数据库reggie,并导入相关表结构和数据。
1、使用navicat工具,在主库新建数据库:
2、空白处点右键,选择运行sql文件,导入表结构和数据:
3、redis数据库要打开
1.3.2 代码构造
在项目中加入Sharding-JDBC实现读写分离步骤,和1.2.3节步骤一样。新建一个分支v1.1,在该分支上操作:
1、导入maven坐标
2、在配置文件中配置读写分离规则
3、在配置文件中配置允许bean定义覆盖配置项
测试没问题之后,将该v1.1分支提交推送到远程仓库。
回到主分支后,将v1.1分支合并至主分支。
2. Nginx
2.1 Nginx概述
Nginx是一款轻量级的web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx的网站有:百度、京东、新浪、网易、腾讯、淘宝等。
Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点开发的,第一个公开版本0.1.e发布于2004年10月4日。
2.1.1 下载安装
可以到Nginx官方网站下载Nginx的安装包,地址为: https://nginx.org/en/download.html
为虚拟机安装Nginx过程:
1、安装依赖包yum -y install gcc pcre-devel zlib-devel openssl openssl-devel
2、下载Nginx安装包wget https://nginx.org/download/nginx-1.16.1.tar.gz
(需要先yum install wget
)
3、解压tar -zxvf nginx-1.16.1.tar.gz
4、cd nginx-1.16.1
5、./configure --prefix=/usr/local/nginx
将nginx安装到指定目录/usr/local/nginx(先提前创建好该目录mkdir -p /usr/local/nginx
)
6、make && make install
先编译,后安装
注:上面第2步,我是在本地从网络下载,再远程传到虚拟机的。本地下载下来的安装包是.tar格式,因此第3步,使用tar -xf nginx-1.16.1.tar命令。后续步骤相同。
2.1.2 Nginx目录结构
安装完Nginx后,我们先来熟悉—下Nginx的目录结构,如图:
重点目录/文件:
conf/nginx.conf | nginx配置文件 |
---|---|
html | 存放静态文件 (htmI、css、Js等) |
logs | 日志目录,存放日志文件 |
sbin/nginx | 二进制文件,用于启动、停止Nginx服务 |
2.2 Nginx命令
2.2.1 查看版本
查看Nginx版本,可以先cd /usr/local/nginx/sbin
,然后在sbin目录下使用命令:./nginx -v
2.2.2 检查配置文件正确性
在启动Nginx服务之前,可以先检查一下conf/nginx.conf文件配置是否有错误,命令为:./nginx -t
2.2.3 启动和停止nginx服务
在sbin目录下执行以下命令
1、启动Nginx服务:./nginx
在浏览器输入服务器地址,默认端口80。如果访问不到,关闭防火墙systemctl stop firewalld
2、启动完成后可以查看Nginx进程:ps -ef|grep nginx
3、停止Nginx服务:./nginx -s stop
2.2.4 重新加载配置文件
当修改Nginx配置文件(/usr/local/nginx/conf目录下的nginx.conf)后,需要重新加载才能生效,可以使用命令重新加载配置文件:./nginx -s reload
配置环境变量:
将nginx二进制文件路径配置到系统环境变量中,这样在sbin目录之外的其他目录下,也可以使用nginx命令。
1、vim /etc/profile
2、在PATH中追加路径
PATH=/usr/local/nginx/sbin:$JAVA_HOME/bin:$PATH
3、source /etc/profile 使之生效
2.3 Nginx配置文件结构
Nginx配置文件(conf/nginx.conf)整体分为三部分:
- 全局块 和Nginx运行相关的全局配置
- events块 和网络连接相关的配置
- http块 代理、缓存、日志记录、虚拟主机配置
- http全局块
- Server块
- Server全局块
- location块
注意:http块中可以配置多个Server块,每个Server块中可以配置多个location块。
2.4 Nginx具体应用
2.4.1 部署静态资源
Nginx可以作为静态web服务器来部署静态资源。静态资源指在服务端真实存在并且能够直接展示的一些文件,比如常见的html页面、css文件、js文件、图片、视频等资源。
相对于Tomcat,Nginx处理静态资源的能力更加高效,所以在生产环境下,一般都会将静态资源部署到Nginx中。
将静态资源部署到Nginx非常简单,只需要将文件复制到Nginx安装目录(/usr/local/nginx)下的html目录中即可。
Nginx配置文件(conf/nginx.conf)中的server块:
1 | server { |
注:server块可以配置多个。
2.4.2 反向代理
1、正向代理vs反向代理
正向代理
是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。
例如,通过代理服务器访问谷歌:
正向代理的典型用途是为在防火墙内的局域网客户端提供访问lnternet的途径。
正向代理一般是在客户端设置代理服务器(客户端知道有代理服务器存在),通过代理服务器转发请求,最终访问到目标服务器。
反向代理
反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源,反向代理服务器负责将请求转发给目标服务器。
(客户端不需要知道反向代理服务器存在)用户不需要知道目标服务器的地址,也无须在用户端作任何设定。
来自网友的总结,可供参考:
正向代理是客户端的代理,帮助客户端访问其无法访问的服务器资源。
反向代理是服务器的代理,帮助服务器做负载均衡,安全防护等。
2、配置反向代理
步骤:
在反向代理服务器192.168.138.100中安装、启动nginx。
在IDEA中编写java程序。此处编写了简单的HelloController。
1
2
3
4
5
6
7
8
9
public class HelloController {
public String hello(){
System.out.println("hello world...");
return "8080";
}
}将程序打jar包,传至web服务器192.168.138.101。
在web服务器192.168.138.101中部署该java程序
java -jar helloworld-1.0-SNAPSHOT.jar
配置反向代理
- 在反向代理服务器192.168.138.100中,在/usr/local/nginx/conf下,修改配置文件
vim nginx.conf
,将下面配置加入配置文件。
1
2
3
4
5
6
7
8server {
listen 82;
server_name localhost;
location / {
proxy_pass http://192.168.138.101:8080; #反向代理配置,将请求转发至指定服务
}
}- 重新加载配置文件
nginx -s reload
- 在反向代理服务器192.168.138.100中,在/usr/local/nginx/conf下,修改配置文件
请求反向代理服务器的82端口192.168.138.100:82/hello(记得关闭82端口防火墙),就会将请求转发至192.168.138.101:8080/hello。
2.4.3 负载均衡
负载均衡介绍:
早期的网站流量和业务功能都比较简单,单台服务器就可以满足基本需求。但是随着互联网的发展,业务流量越来越大,并且业务逻辑也越来越复杂,单合服务器的性能及单点故障问题就凸显出来了。因此需要多台服务器组成应用集群,进行性能的水平扩展以及避免单点故障出现。
- 应用集群:将同一应用部署到多台机器上,组成应用集群。接收负载均衡器分发的请求,进行业务处理并返回响应数据。
- 负载均衡器:根据对应的负载均衡算法,将用户请求分发到应用集群中的一台服务器进行处理。
配置负载均衡:
步骤:
在IDEA中编写另一个java程序。此处HelloController方法返回值改为8081,并修改application.yml中的端口号为8081。将此java程序打包为helloworld-1.0-SNAPSHOT2.jar。
1
2
3
4
5
6
7
8
9
public class HelloController {
public String hello(){
System.out.println("hello world...");
return "8081";
}
}将jar包传至web服务器192.168.138.101。
在web服务器192.168.138.101中部署该java程序
java -jar helloworld-1.0-SNAPSHOT2.jar
,用192.168.138.101:8081和前面已经部署的192.168.138.101:8080代表两个服务器。配置负载均衡
在nginx服务器192.168.138.100中,在/usr/local/nginx/conf下,修改配置文件
vim nginx.conf
,将下面配置加入配置文件。1
2
3
4
5
6
7
8
9
10
11
12upstream targetserver{ # upstream指令可以定义一组服务器
server 192.168.138.101:8080;
server 192.168.138.101:8081;
}
server {
listen 8080;
server_name localhost;
location / {
proxy_pass http://targetserver;
}
}其中,upstream是固定指令;targetserver表示一组服务器集群,可修改名字,只要与proxy_pass中相对应即可。
重新加载配置文件
nginx -s reload
当请求nginx服务器8080端口(192.168.138.100:8080/hello),就会根据负载均衡算法,转发至targetserver其中的一台服务器。(记得关闭web服务器192.168.138.101的8081端口防火墙)
负载均衡策略:
例如:
1 | upstream targetserver{ # upstream指令可以定义一组服务器 |
权重越大,被分发到该服务器的几率越大。