文章目录
- 一、读写分离
- 问题分析
- MySQL主从复制
- 介绍
- 配置
- 配置主库,我这里就用虚拟机上的mysql当主库了
- 配置从库,我这里就用我的另一台克隆的虚拟机了
- 读写分离案例
- 背景
- Sharding-JDBC介绍
- 项目实现读写分离
- 二、Nginx
- 简介
- Nginx的下载和安装
- 安装过程:
- Nginx目录结构
- Nginx配置文件结构
- Nginx命令
- 查看版本
- 检查配置文件正确性
- 启动与停止
- 修改环境变量
- Nginx具体应用
- 部署静态资源
- 反向代理
- 配置反向代理
- 负载均衡
- 负载均衡策略
- Nginx的特点
- 三、前后端分离开发
- 介绍
- 开发流程
- Swagger
- 介绍
- 使用方式
- 项目部署(完结!)
- 配置环境说明
- 部署前端项目
- 部署后端项目
一、读写分离
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
问题分析
目前我们所有的读和写的压力都是由一台数据库来承担,
如果数据库服务器磁盘损坏,则数据会丢失(没有备份)
解决这个问题,就可以用MySQL的主从复制,写操作交给主库,读操作交给从库
同时将主库写入的内容,同步到从库中
MySQL主从复制
介绍
MySQL主从复制是一个异步的复制过程,底层是基于Mysql数据库自带的二进制日志功能。就是一台或多台NysQL数据库(slave,即从库)从另一台MySQL数据库(master,即主库)进行日志的复制然后再解析日志并应用到自身,最终实现从库的数据和主库的数据保持一致。MySQL主从复制是MySQL数据库自带功能,无需借助第三方工具。
MySQL复制过程分成三步:
1.master将改变记录到二进制日志(binary log)
2.slave将master的binary log拷贝到它的中继日志(relay log)
3.slave重做中继日志中的事件,将改变应用到自己的数据库中
配置
前置条件
准备好两台服务器,分别安装MySQL并启动服务成功,我这里用的两台虚拟机(另一台是克隆的,记得修改克隆虚拟机的MySQL的UUID)
修改克隆机的MySQL的uuid
1、登录克隆机的MySQL
2、执行SQL语句,记住生成的uuid,待会需要用
mysql> select uuid();
+--------------------------------------+
| uuid() |
+--------------------------------------+
| 26532364-4f8d-11ed-a300-005056307198 |
+--------------------------------------+
3、查看配置文件目录
mysql> show variables like 'datadir';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| datadir | /var/lib/mysql/ |
+---------------+-----------------+
4、编辑配置文件目录,修改uuid为刚刚我们生成的uuid
vi /var/lib/mysql/auto.cnf
5、重启服务
service mysqld restart
配置主库,我这里就用虚拟机上的mysql当主库了
修改MySQL数据库的配置文件,虚拟机是/etc/my.cnf
找到[mysqld],在下面插入两行
og_bin=mysql-bin #[必须]启用二进制日志
server-id=128 #[必须]服务器唯一ID,只需要确保其id是唯一的就好
重启mysql服务
systemctl restart mysqld
登录Mysql数据库,执行下面的SQL
grant replication slave on *.* to 'Kyle'@'%' identified by 'root';
上面的SQL的作用是创建一个用户Kyle,密码为root,并且给Kyle用户授予replication slave权限,常用语建立复制时所需要用到的用户权限,也就是slave必须被master授权具有该权限的用户,才能通过该用户复制,这是因为主库和从库之间需要互相通信,处于安全考虑,只有通过验证的从库才能从主库中读取二进制数据
登录Mysql数据库,执行下面的SQL
show master status;
记录下结果中File和Position的值
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000005 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
配置从库,我这里就用我的另一台克隆的虚拟机了
1、修改MySQL数据库的配置文件/etc/my.cnf
找到[mysqld],在下面插入一行
server-id=127 #[必须]服务器唯一ID,只需要确保其id是唯一的就好
2、重启mysql服务
systemctl restart mysqld
3、登录Mysql数据库,执行下面的SQL,将参数修改为自己的
change master to master_host='192.168.238.131',master_user='Kyle',master_password='root',master_log_file='mysql-bin.000005',master_log_pos=154;
start slave;
4、登录Mysql数据库,执行SQL,查看从库的状态
show slave status;
看到如下如下三行配置相同,则主从连接成功
Slave_IO_State: Waiting for master to send event
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
如果Slave_IO_Running: 为 No就需要检查uuid是否修改成功了
读写分离案例
背景
面对日益增加的系统访问量,数据库的吞吐量面临着巨大的瓶颈。
对于同一时刻有大量并发读操作和较少的写操作类型的应用系统来说,将数据库拆分为主库和从库
主库主要负责处理事务性的增删改操作
从库主要负责查询操作
这样就能有效避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善
Sharding-JDBC介绍
Sharding-JDBC定位为轻量级的JAVA框架,在JAVA的JDBC层提供额外的服务,它使得客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架
使用Sharding-JDBC可以在程序中轻松的实现数据库读写分离
适用于任何基于JDBC的ORM框架
支持任何第三方的数据库连接池
支持任意实现JDBC规范的数据库
使用Sharding-JDBC框架的步骤
1、导入对应的maven坐标
2、在配置文件中配置读写分离规则
3、在配置文件中配置允许bean定义覆盖配置项
项目实现读写分离
前面我们已经配置好了主从数据库,那么我们现在就用项目试试读写分离
1、导入项目的SQL数据
2、Git创建一个新分支v1.1,便于我们提交维护
3、导入Sharding-JDBC的maven坐标
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
4、在配置文件中配置读写分离规则,配置允许bean定义覆盖配置项
server:
port: 8080
spring:
shardingsphere:
datasource:
names:
master,slave
# 主数据源
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.88.129:3306/reggie?characterEncoding=utf-8&useSSL=false
username: root
password: root
# 从数据源
slave:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.88.128:3306/reggie?characterEncoding=utf-8&useSSL=false
username: root
password: root
masterslave:
# 读写分离配置
load-balance-algorithm-type: round_robin #轮询
# 最终的数据源名称
name: dataSource
# 主库数据源名称
master-data-source-name: master
# 从库数据源名称列表,多个逗号分隔
slave-data-source-names: slave
props:
sql:
show: true #开启SQL显示,默认false
main:
allow-bean-definition-overriding: true
allow-circular-references: true
cache:
redis:
time-to-live: 1800000
redis:
host: localhost
port: 6379
database: 0
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: ASSIGN_ID
二、Nginx
简介
Nginx是一款轻量级的Web/反向代理服务器以及电子邮件(IMAP/POP3)代理服务器,其特点是占有内存少,并发能力强。
事实上Nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用Nginx的网站有:百度、京东、新浪、网易、腾讯、淘宝等。
Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Pam6nep)开发的,第一个公开版本0.1.0发布于2004年10月4日。
官网:https://nginx.org/
Nginx的下载和安装
官网下载链接:https://nginx.org/en/download.html
安装过程:
1、Nginx是C语言开发的,所以需要先安装依赖
yum -y install gcc pcre-devel zlib-devel openssl openssl-devel
2、下载Nginx安装包
wget https://nginx.org/download/nginx-1.22.1.tar.gz
3、解压,我习惯放在/usr/local目录下
tar -zxvf nginx-1.22.1.tar.gz -C /usr/local/
4、进入到我们解压完毕后的文件夹内
cd /usr/local/nginx-1.22.1/
5、建安装路径文件夹
mkdir /usr/local/nginx
6、安装前检查工作
./configure --prefix=/usr/local/nginx
7、编译并安装
make && make install
Nginx目录结构
安装完Nginx后,我们先来熟悉一下Nginx的目录结构
重点目录/文件:
conf/nginx.conf
nginx配置文件
html
存放静态文件(html、css、Js等)
logs
日志目录,存放日志文件
sbin/nginx
二进制文件,用于启动、停止Nginx服务
文件目录树状图如下
.
├── conf <-- Nginx配置文件
│ ├── fastcgi.conf
│ ├── fastcgi.conf.default
│ ├── fastcgi_params
│ ├── fastcgi_params.default
│ ├── koi-utf
│ ├── koi-win
│ ├── mime.types
│ ├── mime.types.default
│ ├── nginx.conf <-- 这个文件我们经常操作
│ ├── nginx.conf.default
│ ├── scgi_params
│ ├── scgi_params.default
│ ├── uwsgi_params
│ ├── uwsgi_params.default
│ └── win-utf
├── html <-- 存放静态文件,我们后期部署项目,就要将静态文件放在这
│ ├── 50x.html
│ └── index.html <-- 提供的默认的页面
├── logs <-- 日志目录,由于我们新装的Nginx,所以现在还没有日志文件
└── sbin
└── nginx <-- 这个文件我们也经常操作
Nginx配置文件结构
Nginx配置文件(conf/nginx.conf)整体分为三部分
全局块
Nginx运行相关的全局配置
events块
网络连接相关的配置
http块
代理、缓存、日志记录、虚拟主机配置
http全局块
Server块
· Server全局块
· location块
worker_processes 1; <-- 全局块
events { <-- events块
worker_connections 1024;
}
http { <-- http块
include mime.types; <-- http全局块
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server { <-- Server块
listen 80; <-- Server全局块
server_name localhost;
location / { <-- location块
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
注意:http块中可以配置多个Server块,每个Server块中可以配置多个location块
Nginx命令
查看版本
进入sbin目录,输入./nginx -v
[root@localhost sbin]# ./nginx -v
nginx version: nginx/1.22.1
检查配置文件正确性
进入sbin目录,输入./nginx -t,如果有错误会报错,而且也会记日志
[root@localhost sbin]# ./nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
启动与停止
进入sbin目录,输入./nginx,启动完成后查看进程
[root@localhost sbin]# ./nginx
[root@localhost sbin]# ps -ef | grep nginx
root 89623 1 0 22:08 ? 00:00:00 nginx: master process ./nginx
nobody 89624 89623 0 22:08 ? 00:00:00 nginx: worker process
root 89921 1696 0 22:08 pts/0 00:00:00 grep --color=auto nginx
如果想停止Nginx服务,输入./nginx -s stop,停止服务后再次查看进程
[root@localhost sbin]# ./nginx -s stop
[root@localhost sbin]# ps -ef | grep nginx
root 93772 1696 0 22:11 pts/0 00:00:00 grep --color=auto nginx
重新加载配置文件
当修改Nginx配置文件后,需要重新加载才能生效,可以使用下面命令重新加载配置文件:./nginx -s reload。
修改环境变量
上面的所有命令,都需要我们在sbin目录下才能运行,比较麻烦,所以我们可以将Nginx的二进制文件配置到环境变量中,这样无论我们在哪个目录下,都能使用上面的命令
使用vim /etc/profile命令打开配置文件,并配置环境变量,保存并退出
- PATH=$JAVA_HOME/bin:$PATH
+ PATH=/usr/local/nginx/sbin:$JAVA_HOME/bin:$PATH
之后重新加载配置文件,使用source /etc/profile命令,然后我们在任意位置输入nginx即可启动服务,nginx -s stop即可停止服务
查看自己IP,启动服务后,浏览器输入ip地址就可以访问Nginx的默认页面
ip addr
Nginx具体应用
部署静态资源
Nginx可以作为静态web服务器来部署静态资源。静态资源指在服务端真实存在并且能够直接展示的一些文件,比如常见的html页面、css文件、js文件、图片、视频等资源。
相对于Tomcat,Nginx处理静态资源的能力更加高效,所以在生产环境下,一般都会将静态资源部署到Nginx中。
将静态资源部署到Nginx非常简单,只需要将文件复制到Nginx安装目录下的html目录中即可。
反向代理
正向代理
正向代理是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。
正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。
正向代理一般是在客户端设置代理服务器,通过代理服务器转发请求,最终访问到目标服务器。
反向代理
反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源,反向代理服务器负责将请求转发给目标服务器。
用户不需要知道目标服务器的地址,也无须在用户端作任何设定。
举个例子
正向代理:你让舍友去给你带三楼卖的煎饼(你最终会得到一个三楼的煎饼)
反向代理:你让舍友去给你买煎饼(你最终只会得到一个煎饼,但你不知道煎饼是哪儿卖的)
和正向代理不同,反向代理相当于是为目标服务器工作的,当你去访问某个网站时,你以为你访问问的是目标服务器,其实不然,当你访问时,其实是由一个代理服务器去接收你的请求,正向代理与反向代理最简单的区别: 正向代理隐藏的是用户(卖煎饼的不知道是你要买),反向代理隐藏的是服务器(你不知道煎饼是谁卖的)。
正向代理侧重的是用户,用户知道可以通过代理访问无法访问的资源,而反向代理侧重点在服务器这边,用户压根不知道自己访问的是资源时通过代理人去转发的。
配置反向代理
这里是在192.168.88.129上配置的,那么访问流程如下
客户端 —>192.168.88.129:82 —> 192.168.88.128/50x.html
客户端访问反向代理服务器的82端口,而82端口又将请求转发给web服务器的50x.html资源
注意这里需要开启反向代理服务器的82端口
server {
listen 82;
server_name localhost;
location / {
proxy_pass http://http://192.168.238.132/50x.html;
}
}
负载均衡
早期的网站流量和业务功能都比较简单,单台服务器就可以满足基本需求,但是随着互联网的发展,业务流量越来越大并且业务逻辑也越来越复杂,单台服务器的性能及单点故障问题就凸显出来了,因此需要多台服务器组成应用集群,进行性能的水平扩展以及避免单点故障出现。
应用集群:将同一应用部署到多台机器上,组成应用集群,接收负载均衡器分发的请求,进行业务处理并返回响应数据。
负载均衡器:将用户请求根据对应的负载均衡算法分发到应用集群中的一台服务器进行处理。
配置负载均衡
默认是轮询算法,第一次访问是192.168.238.132,第二次访问是101.XXX.XXX.160
也可以改用权重方式,权重越大,几率越大,现在的访问三分之二是第一台服务器接收,三分之一是第二台服务器接收
server 192.168.238.132 weight=10
server 101.XXX.XXX.160 weight=5
upstream targetServer{
server 192.168.238.132;
server 101.XXX.XXX.160;
}
server {
listen 82;
server_name localhost;
location / {
proxy_pass http://targetServer;
}
}
负载均衡策略
名称 | 说明 |
---|---|
轮询 | 默认方式 |
weight | 权重方式 |
ip_hash | 依据ip分配方式 |
least_conn | 依据最少连接方式 |
url_hash | 依据url分配方式 |
fair | 依据响应时间方式 |
Nginx的特点
1、跨平台:Nginx可以在大多数操作系统中运行,而且也有Windows的移植版本
2、配置异常简单:非常容易上手。配置风格跟程序开发一样,神一般的配置
3、非阻塞、高并发:数据复制时,磁盘I/O的第一阶段是非阻塞的。官方测试能够支撑5万并发连接,4、在实际生产环境中跑到2-3万并发连接数(这得益于Nginx使用了最新的epoll模型)
事件驱动:通信机制采用epoll模式,支持更大的并发连接数
5、内存消耗小:处理大并发的请求内存消耗非常小。在3万并发连接下,开启的10个Nginx进程才消耗150M内存(15M*10=150M)
6、成本低廉:Nginx作为开源软件,可以免费试用。而购买F5 BIG-IP、NetScaler等硬件负载均衡交换机则需要十多万至几十万人民币
7、内置健康检查功能:如果Nginx Proxy后端的某台Web服务器宕机了,不会影响前端访问。
8、节省带宽:支持GZIP压缩,可以添加浏览器本地缓存的Header头。
9、稳定性高:用于反向代理,宕机的概率微乎其微。
三、前后端分离开发
开发人员同时负责前端和后端代码开发,分工不明确,开发效率低
前后端代码混合在一个工程中,不便于管理
对开发人员要求高,人员招聘困难
所以衍生出了一种前后端分离开发
介绍
前后端分离开发,就是在项目开发过程中,对前端代码的开发,专门由前端开发人员负责,后端代码由后端开发人员负责,这样可以做到分工明确,各司其职,提高开发效率,前后端代码并行开发,可以加快项目的开发速度。目前,前后端分离开发方式已经被越来越多的公司采用了,成为现在项目开发的主流开发方式。
前后端分离开发后,从工程结构上也会发生变化,即前后端代码不再混合在同一个maven工程中,而是分为前端工程和后端工程
开发流程
前后端开发人员都参照接口API文档进行开发
接口(API接口) 就是一个http的请求地址,主要就是去定义:请求路径、请求方式、请求参数、响应参数等内容。
Swagger
介绍
使用Swagger你只需要按照它的规范去定义接口及接口相关的信息,再通过Swagger衍生出来的一系列项目和工具,就可以做成各种格式的接口文档,以及在线接口调试页面等。
官网:https://swagger.io/
使用方式
1、导入对应的maven坐标
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
2、导入knife4j相关配置,并配置静态资源映射,否则接口文档页面无法访问,注意将controller的包路径修改为你自己的
@Slf4j
@Configuration
@EnableSwagger2
@EnableKnife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
* 设置静态资源映射
* @param registry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("开始进行静态资源映射...");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
/**
* 扩展mvc框架的消息转换器
* @param converters
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
//创建消息转换器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器,底层使用Jackson将Java对象转为json
messageConverter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息转换器对象追加到mvc框架的转换器集合中
converters.add(0,messageConverter);
}
@Bean
public Docket createRestApi() {
// 文档类型
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.itheima.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("瑞吉外卖")
.version("1.0")
.description("瑞吉外卖接口文档")
.build();
}
}
4、启动服务,访问 http://localhost/doc.html 即可看到生成的接口文档,我这里的端口号用的80,根据自己的需求改
项目部署(完结!)
配置环境说明
一共需要三台服务器
192.168.88.129(服务器A)
Nginx:部署前端项目、配置反向代理
MySql:主从复制结构中的主库
192.168.88.129(服务器B)
jdk:运行java项目
git:版本控制工具
maven:项目构建工具
jar:Spring Boot 项目打成jar包基于内置Tomcat运行
MySql:主从复制结构中的从库
本地(服务器C)
Redis:缓存中间件
部署前端项目
1、在服务器A中安装Nginx,将前端项目打包目录上传到Nginx的html目录下
2、修改Nginx配置文件nginx.conf,新增如下配置
server {
listen 80;
server_name localhost;
location / {
root html/dist;
index index.html;
}
location ^~ /api/ {
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://192.168.238.132;
}
}
部署后端项目
在服务器B中安装JDK,Git,MySql
将项目打成jar包,手动上传并部署(当然你也可以选择git拉取代码,然后shell脚本自动部署)
部署完后端项目之后,我们就能完成正常的登录功能了,也能进入到后台系统进行增删改查操作