前言
单台MySQL数据库服务器最多支持2000并发,单台Tomcat服务器最多支持400个并发;
针对MySQL数据库、Web应用(Tomcat)单个节点负载压力过大的系统瓶颈;
我们可以采用Nginx反向代理+Web应用读写分离+MySQL主从的架构进行优化;
一、MySQL主从复制
当1台MySQL服务器承担了读、写操作之后,这台服务器的压力是比较大的;
MySQL主从复制的思想是:责任分工从而避免单点压力过大, 写数据的操作由MySQL主库负责,读数据的操作由MySQL从库负责;
MySQL主从架构的优势
-
高可用,实时灾备,用于故障切换。比如主库挂了,可以切从库。
-
读写分离,提供查询服务,减少主库压力,提升性能
-
备份数据,避免影响业务。
1.介绍
-
主库在数据更新提交事务之前,将事件异步记录到binlog二进制日志文件中,日志记录完成后,存储引擎提交本次事务;
-
从库启动一个I/O线程与主库建立连接,用来请求主库中要更新的binlog。这时主库创建的binlog dump线程,这是二进制日志转储经线程,如果有新更新的事件,就通知从库的I/O线程,当该线程转储二进制日志完成,没有新的日志时,该线程进入sleep状态。
-
从库的I/O线程接收到新的事件日志后,先从主库读取bin-log,再写入到从库的relay log(中继日志)中。
-
从库的SQL线程读取中继日志中的事件,并执行更新保存。
2.实现
实现MySQL的主从复制其实非常简单,只需要对MySQL进行简单的配置即可;
2.1.
提前准备2台服务器,并且在服务器中安装MySQL,服务器的信息如下:
数据库 | IP | 数据库版本 |
---|---|---|
Master | 192.168.56.18 | 5.5.49-log |
Slave | 192.168.56.19 |
2.2.防火墙设置
分别修改两台服务器的防火墙策略,放行3306端口;
firewall-cmd --zone=public --add-port=3306/tcp --permanent firewall-cmd --reload firewall-cmd --zone=public --list-ports
2.3.主库配置
下面操作仅仅在master库上执行
1. 开启二进制日志
修改mysql的配置文件/etc/my.cnf
[mysqld] log-bin=mysql-bin #[必须]启用二进制日志(当前默认已开启) server-id=1 #[必须]服务器唯一ID(当前默认就是1)
2.重启mariadb
[root@localhost ~]# systemctl restart mariadb
3.创建账户并授权
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* to 'zhanggen'@'%' identified by '123.com'; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> show master status; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000001 | 392 | | | +------------------+----------+--------------+------------------+ 1 row in set (0.00 sec)
4.查看主库状态
MariaDB [(none)]> show master status; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000001 | 392 | | | +------------------+----------+--------------+------------------+
2.4.从库配置
如果条件运行我们可以配置1主多从架构;
当MySQL主从架构搭建成功之后,一定不要操作从库;只需要操作主库;
1.修改从库配置文件
修改mysql的配置文件/etc/my.cnf,保证下面两项
[mysqld] log-bin=mysql-bin #[必须]启用二进制日志(当前默认已开启) server-id=2 #[必须]服务器唯一ID(当前默认1,必须手动修改成2)
2.重启mariadb
[root@localhost ~]# systemctl restart mariadb
3.登录从库
mysql -u root -p
4.执行
如果我们已经设置了主从可以在执行以下命令之前,执行stop slave;
ariaDB [(none)]> system clear; MariaDB [(none)]> change master to master_host='192.168.56.18', master_user='zhanggen', master_password='123.com', master_log_file='mysql-bin.000001', master_log_pos=392; Query OK, 0 rows affected (0.01 sec) MariaDB [(none)]> start slave; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.56.18 Master_User: zhanggen Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 392 Relay_Log_File: mariadb-relay-bin.000002 Relay_Log_Pos: 529 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 392 Relay_Log_Space: 825 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 1 row in set (0.00 sec) ERROR: No query specified MariaDB [(none)]>
3.测试
二、Spring读写分离
当MySQL的架构变成主从架构之后,Java程序调用数据库的时候,也应该作出调整,否则没有意义;
-
适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
-
支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
-
CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, `address` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2.添加pom依赖
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.itheima</groupId> <artifactId>rw-demo</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.5</version> <relativePath/> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.0.0-RC1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> <scope>runtime</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.23</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.4.5</version> </plugin> </plugins> </build> </project>
3.添加配置文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
spring: shardingsphere: datasource: names: db1,db2 # 主库数据源 db1: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.56.18:3306/reggieRW?useUnicode=true&characterEncoding=utf-8&useSSL=false username: zhanggen password: 123.com # 从库数据源 db2: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.56.19:3306/reggieRW?useUnicode=true&characterEncoding=utf-8&useSSL=false username: zhanggen password: 123.com masterslave: # 读写分离配置 load-balance-algorithm-type: round_robin #轮询 # 最终的数据源名称 name: dataSource # 主库数据源名称 master-data-source-name: db1 # 从库数据源名称列表,多个逗号分隔 slave-data-source-names: db2 props: sql: show: true #开启SQL显示,默认false main: #该配置项的目的,就是如果当前项目中存在同名的bean,后定义的bean会覆盖先定义的。 allow-bean-definition-overriding: true
三、Nginx
Nginx工作在OSI的应用层,可以这对HTTP应用做一些分流策略;
Nginx可以部署HTML、JS、CSS、 Image、 Video等静态资源,实现网站的前后端、动静分离;
- 轮询: 根据请求数量平均分配;(模式)
- weight: 根据权重分发请求,权重大的分配到请求的概率大;
- ip_hash: 根据客户端请求的IP地址计算hash值, 根据hash值来分发请求, 同一个IP发起的请求, 会发转发到同一个服务器上;
- url_hash: 根据客户端请求url的hash值分发请求, 同1个url请求, 会发转发到同1台服务器上,所以开发人员在开发Web层时,把不同业务逻辑都放在同1个URL下,否则在这种策略模式下,会导致负载不均衡现象;
- least_conn: 根据当前哪1台服务器处理的连接数最少, 请求优先转发到这1台服务器;
- fair: 优先把请求分发到处理请求时间短的服务器;
负载均衡就是部署多台Tomcat分摊单台Tomcat负载压力;
# 声明负载均衡
upstream tomcatserver{
server 192.168.56.18:8082 weight=2;
server 192.168.56.19:8083 weight=1;
}
server {
listen 80;
server_name localhost;
location / {
# 声明反向代理
proxy_pass http://tomcatserver;
}
}