对于性能优化这一个词,一直以来都是在开发过程中占据比较重要的地位,一般我们都是不仅仅需要考虑到这个程序如何开发,还要思考怎么去优化这个程序,比如运行速度、并发处理、内存优化等,那么我们今天就数据库这一块的并发处理来做个简单讲解。
一般项目比较小的情况下,我们是一般不需要考虑数据库这块的并发问题的,当然我们也得考虑服务器宕机的情况,这个就不做过多的解释。但是当我们的项目比较大的时候,我们就得考虑数据库能不能处理高并发的现象了,那么我们数据库一般是怎么处理高并发的情况呢?首先我们可以做一个数据库的主从同步,也就是说我们可以用多台数据库形成一个数据库集群来解决高并发的情况。
主从同步介绍
那么问题来了,什么叫做主从同步?
- 在多态数据服务器中,分为主服务器和从服务器。一台主服务器对应多态从服务器。
- 主服务器只负责写入数据,从服务器只负责同步主服务器的数据,并让外部程序读取数据。
- 主服务器写入数据后,即刻将写入数据的命令发送给从服务器,从而使得主从数据同步。
- 应用程序可以随机读取某一台从服务器的数据这样就可以分摊读取数据的压力,从而解决高并发的读取数据问题。
- 当从服务器不能工作时,整个系统将不受影响;当主服务器不能工作时,可以方便的从从服务器选取一台来当主服务器,因为主从服务器之间随时都是有交互的,通过多台服务器之间的连接判断,就可以判断哪台服务器是否宕机的情况,同时也解决了服务器宕机的情况。
主从同步的优点
- 提高读写性能:设置了主从不同之后,数据写入和读取是在不同的服务器上进行的,而且可以通过增加从服务器来提高数据库的读取性能。
- 提高数据安全:因为数据已复制到从服务器,可以在从服务器上备份而不破坏主服务器响应数据。
主从同步的工作原理
MySQL的主从同步是一个异步的复制过程,数据将从一个MySQL数据库(这里我们称之为Master)复制到另一个MySQL数据库(这里我们称之为Slave),在Master和Slave之间实现整个主从复制的过程是由三个线程参与完成的。其中有两个线程(SQL线程和IO线程)在Slave端,另一个线程(I/O线程)则在Master端。
要实现MySQL的主从同步,首先必须打开Master端的Binary Log记录功能,否则无法实现。因为整个复制过程实际上就是Slave从Master端获取Binary Log日志,然后再在Slave上以相同顺序获取Binary Log日志中记录的各种SQL操作,从而将这些数据保存下来。
主从同步的操作流程
- 在Slave 服务器上执行sart slave命令开启主从复制开关,开始进行主从复制。
- 此时,Slave服务器的IO线程会通过在master上已经授权的复制用户权限请求连接master服务器,并请求从执行Binary Log日志文件的指定位置(日志文件名和位置就是在配置主从复制服务时执行change master命令指定的)之后开始发送Binary Log日志内容。
- Master服务器接收到来自Slave服务器的IO线程的请求后,其上负责复制的IO线程会根据Slave服务器的IO线程请求的信息分批读取指定Binary Log日志文件指定位置之后的Binary Log日志信息,然后返回给Slave端的IO线程。返回的信息中除了Binary Log日志内容外,还有在Master服务器端记录的IO线程。返回的信息中除了Binary Log中的下一个指定更新位置。
- 当Slave服务器的IO线程获取到Master服务器上IO线程发送的日志内容、日志文件及位置点后,会将Binary Log日志内容依次写到Slave端自身的Relay Log(即中继日志)文件(http://Mysql-relay-bin.xxx)的最末端,并将新的Binary Log文件名和位置记录到master-info文件中,以便下一次读取master端新Binary Log日志时能告诉Master服务器从新Binary Log日志的指定文件及位置开始读取新的Binary Log日志内容。
- Slave服务器端的SQL线程会实时检测本地Relay Log 中IO线程新增的日志内容,然后及时把Relay LOG 文件中的内容解析成sql语句,并在自身Slave服务器上按解析SQL语句的位置顺序执行应用这样sql语句,并在http://relay-log.info中记录当前应用中继日志的文件名和位置点。
主从同步环境搭建
我们准备的是多实例,一台服务器开启三个不同服务端口
[root@db02 3307]# netstat -lntup|grep 330
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 3074/mysql
tcp 0 0 0.0.0.0:3307 0.0.0.0:* LISTEN 33364/mysq
tcp 0 0 0.0.0.0:3308 0.0.0.0:* LISTEN 34084/mysq
主库开启Binary Log功能
[root@db02 3307]# grep log-bin /data/3306/my.cnf
log-bin = /data/3306/mysql-bin
设置server-id,此处ID不可以相同否则最后出现IO错误
[root@db02 3307]# grep server-id /data/3306/my.cnf
server-id = 1
[root@db02 3307]# grep server-id /data/3307/my.cnf
server-id = 3
[root@db02 3307]# grep server-id /data/3308/my.cnf
server-id = 2
======== ================================================
[root@db02 3307]# grep server-id /data/{3306,3307,3308}/my.cnf
/data/3306/my.cnf:server-id = 1
/data/3307/my.cnf:server-id = 3
/data/3308/my.cnf:server-id = 2
主库需要授权slave访问的用户
mysql>grant replication slave on *.* to 'rep'@'10.0.0.%' identified by '123456';
mysql> flush privileges;
mysql>show grants for rep@'172.16.1.%';
mysql>select user,host from mysql.user
因为从库现在还没有数据,或者数据不统一我们需要导入数据
锁表、查看Binary Log文件及位置点,主库导出全备,需要锁表
flush table with read lock; 锁表,窗口不能退出,退出失效
root@oldboy 05:16:22->show master status; 临界点,将来恢复就从0025开始
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000025 | 9155 | | |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
备份
mysqldump -uroot -p123456 -S /data/3306/mysql.sock -A -B --events|gzip >/server/backup/rep_bak$(date +%F).sql.gz
[root@db02 oldboy]# ls -lrt /server/backup/
total 308
-rw-r--r-- 1 root root 20 Dec 23 2015 bak_2015-12-23.sql.gz
-rw-r--r-- 1 root root 152214 Dec 23 2015 bak.sql.gz
-rw-r--r-- 1 root root 152238 Jun 29 17:20 rep_bak2016-06-29.sql.gz
解锁
root@oldboy 05:22:00->show master status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000025 | 9155 | | |
+------------------+----------+--------------+------------------+
从库操作
确保server-id不同
把主库的备份导入到从库
[root@db02 backup]# gzip -d rep_bak2016-06-29.sql.gz
[root@db02 backup]# mysql -uroot -p123456 -S /data/3307/mysql.sock
查找位置点,配置http://master.info
mysql-bin.000025 | 9155
| 主库的位置点
Mysql从库连接主库的配置信息如下
CHANGE MASTER TO
MASTER_HOST='172.16.1.52', #这是主库的IP(域名也可以需要做解析)
MASTER_PORT=3306, #主库的端口,从库端口和主库不可以相同
MASTER_USER='rep', #这是主库上创建用来复制的用户rep
MASTER_PASSWORD='123456' #rep的密码
MASTER_LOG_FILE='mysql-bin.000025', #这里是show master
status时看到的查询二进制日志文件名称,这里不能多空格
MASTER_LOG_POS=9155; #这里是show master status时看到的二进制日志偏移量,不能多空格
提示:3307操作此步:会在/data/3307/data下面产生master.info文件
开启从库复制开关
root@oldboy 07:47:44->show slave statusG
查看检查结果:在主库创建目录查看从库是否存在即可