分库分表
- 关系型数据库和NoSQL
非关系型数据库: key-value: redis 、memcache ;
面向文档: mongoDB
面向列: HBase
数据切分
mycat
TDDL
Sharding-JDBC
cobar
- 对于存储层的压力知道如何去提供解决方案和思路
- 对分库分表的常用手段有全面了解
- 了解Mysql的主从及binlog
- 知道Mycat及其他相似的中间件
为什么要分库分表
超大容量问题
-
订单表数据量过大
- 单表处理能力有瓶颈
性能问题
-
单一数据库解决所有应用节点
- 单一数据库有性能极限
如何去做到
垂直切分、 水平切分
-
垂直分库
- 解决的是表过多的问题
-
不同的表放在不同的库中
- 比如说订单相关的放在订单库中
-
垂直分表
- 解决单表列过多的问题
-
列多的表拆分成多个列少的表
-
比如说商 品表拆分
- 通过关联关系维持数据
-
水平切分
- 大数据表拆成小表
常见的拆分策略
拆分如果全部放在一个库中,可能会有性能问题。
可能把部分表放在不同的数据库中
拆分维度选择的数据非常重要
垂直拆分
er分片
水平拆分
- 一致性hash
-
范围切分
- 可以按照ID
- 日期拆分
拆分以后带来的问题
跨库join的问题
select a.x ,b.y from a,b on a.id=b.id
-
设计的时候考虑到应用层的join问题。
- 拆分的时候考虑好
- 在服务层去做调用
A服务里查询到一个list
直接通过接口查询
/**
*批量查询不要这样使用
**/
for(list){
bservice.select(list);
}
-
全局表
- 数据变更比较少的基于全局应用的表
- 或者抽离公共服务
-
做字段冗余(空间换时间的做法)
订单表需要展示,商家id 商家名称(因为订单表和商家表是一对一的关系),那么查询的时候可能每一次都需要为了查询商家名称,可以做商家名称字段冗余
商家名称变更解决办法
- 定时任务
- 任务通知
跨分片数据排序分页
在应用层做拼接
唯一主键问题
用自增id做主键,多表情况下自增id会重复
解决方案
-
UUID 性能比较低
- 值比较长
- 导致索引比较大
- 性能比较低
-
snowflake (雪花算法)
- 时间序列
- 机器标志
- 技术顺序号
- 一起组成的完成id
-
mongoDB
- ObjectId
-
zookeeper
- 有序节点,从1开始递增
-
redis自增
- incr
-
数据库表
- 专门一张表来获取id
分布式事务问题
多个数据库表之间保证原子性
性能问题; 互联网公司用强一致性分布式事务比较少,一般使用最终一致性,或者软事物来解决
分库分表最难的在于业务的复杂度;
前提: 水平分表的前提是已经存在大量的业务数据。而这个业务数据已经渗透到了各个应用节点
如何权衡当前公司的存储需要优化
1. 提前规划(主键问题解决、 join问题)
2. 当前数据单表超过1000W、每天的增长量持续上升
Mysql的主从
绝大部分都是写少读多的操作,可以做读写分离,多个读库做压力释放
读库可以实现负载均衡
数据库的版本5.7版本
安装以后文件对应的目录
mysql的数据文件和二进制文件: /var/lib/mysql/
mysql的配置文件: /etc/my.cnf
mysql的日志文件: /var/log/mysql.log
6 为master
- 创建一个用户
repl
,并且允许其他服务器可以通过该用户远程访问master,通过该用户去读取二进制数据,实现数据同步
Create user repl identified by 'repl';
repl用户必须具有REPLICATION SLAVE权限,除此之外其他权限都不需要
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%' IDENTIFIED BY 'repl' ;
2.修改6 etc/my.cnf
配置文件,在[mysqld] 下添加如下配置
log-bin=mysql-bin #启用二进制日志文件
server-id=6 #服务器唯一ID
3.重启数据库
systemctl restart mysqld
4.登录到数据库,通过show master status
查看master的状态信息
118 为slave
- 修改118 my.cnf配置文件, 在[mysqld]下增加如下配置
server-id=118 #服务器id,唯一
relay-log=slave-relay-bin #中继日志,保存master同步过来的信息
relay-log-index=slave-relay-bin.index
read_only=1
- 重启数据库:
systemctl restart mysqld
- 连接到数据库客户端,通过如下命令建立同步连接
change master to master_host='116.62.221.6', master_port=3306,master_user='repl',master_password='repl',master_log_file='mysql-bin.000003',master_log_pos=429;
master_log_pos
表示从主节点哪个位置开始读,
master_log_file
这两个部分从master的show master status
可以找到对应的值,不能随便写。
- 执行
start slave
-
show slave status\G;
-
查看slave服务器状态,当如下两个线程状态为yes,表示主从复制配置成功
Slave_IO_Running=Yes Slave_SQL_Running=Yes
-
主从同步的原理
-
master记录二进制日志。在每个事务更新数据完成之前,master在二日志记录这些改变。MySQL将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master通知存储引擎提交事务
- slave将master的binary log拷贝到它自己的中继日志。首先,slave开始一个工作线程——I/O线程。I/O线程在master上打开一个普通的连接,然后开始binlog dump process。Binlog dump process从master的二进制日志中读取事件,如果已经跟上master,它会睡眠并等待master产生新的事件。I/O线程将这些事件写入中继日志
- SQL线程从中继日志读取事件,并重放其中的事件而更新slave的数据,使其与master中的数据一致
binlog: 用来记录mysql的数据更新或者潜在更新(update xxx where id=x effect row 0);
文件内容存储:/var/lib/mysql
mysqlbinlog --base64-output=decode-rows -v mysql-bin.000001
查看binlog的内容
show binlog events in 'mysql-bin.000001'
查看binlog的日志,不需要看内容
binlog的格式
查看当前日志模式
show variables like '%log%'
-> binlog_format
statement :
基于sql语句的模式。update table set name =””; effect row 1000; uuid、now() other function
row: (默认)
基于行模式; 存在1000条数据变更; 记录修改以后每一条记录变化的值
mixed:
混合模式,由mysql自动判断处理
修改binlog_formater
,通过在mysql客户端输入如下命令可以修改
set global binlog_format='row/mixed/statement';
或者在
vim /etc/my.cnf
的[mysqld]下增加binlog_format='mixed'
主从同步的延时问题
网络延迟比较大
磁盘的读写
主从同步延迟是怎么产生的
- 当master库tps比较高的时候,产生的DDL数量超过slave一个sql线程所能承受的范围,或者slave的大型query语句产生锁等待
- 网络传输: bin文件的传输延迟
- 磁盘的读写耗时:文件通知更新、磁盘读取延迟、磁盘写入延迟
解决方案
-
在数据库和应用层增加缓存处理,优先从缓存中读取数据
- 从缓存中取,同步后然后再从slave中取
- 减少slave同步延迟,可以修改slave库
sync_binlog
属性;sync_binlog=0
设置为0执行ddlbinlog
不会立马刷新到文件中,而是通过文件系统调度刷新 文件系统来调度把
binlog_cache
刷新到磁盘
sync_binlog=n
等于n表示执行n个事物刷新
- 增加延时监控
Nagios
做网络监控mk-heartbeat
心跳监控通过监控做报警
- Mysql的主从配置
- 了解binlog及主从复制原理
MyCat
简介
地址:http://www.mycat.io/
https://github.com/MyCATApach...
相当于代理
作用
- 拦截sql
- 分片
- 路由
- 缓存
- 读写分离
查询如果是分片键那么直接落到对应数据库,如果不是分片键,那么会路由到所有数据库
haproxy负载均衡
keepalive 高可用
配置文件
rlue.xml
分片数据库
对应的rule分片策略
范围分片
schema.xml
逻辑数据库逻辑表
server.xml
配置当前服务
使用
单库大表拆分
跨库分表
读写分离
高可用
分库分表双主(数据双向同步)策略
- 需要通过haProxy做一个集群
- 再对haproxy做一个高可用
数据库分库分表
在互联网行业中,最大的特点是并发量高、数据量大;为了应对这两个特点,后端的技术架构需要使用各种技术来支撑;而这个专题所讲的是关于数据库层面的优化
当数据库的访问量到达一定的瓶颈的时候,当数据库单表数据比较大严重影响ddl性能的时候。我们应该根据什么思路去做优化和调整
- 持久化存储在大型分布式架构下部分需要应对的问题
- 如何去做分库分表
- 拆分策略
- 分库分表带来的问题及解决方案
- 如何知道当前的系统需要做分库分表
- Mysql的读写分离实战
- Mysql主主复制以及基于keepalived实现双主高可用
- 基于HAProxy实现
- 主从同步延迟问题及解决方案
- 认识Mycat及Mycat安装
- Mycat数据切分实战
- Mycat读写分离实战
- Mycat分片策略
- Mycat全局表配置
centos7安装mysql5.7操作步骤
下载mysql的repo源
wget http://repo.mysql.com/mysql57-community-release-el7-8.noarch.rpm
安装源
rpm -ivh mysql57-community-release-el7-8.noarch.rpm
安装数据库
yum install mysql-server
启动数据库
systemctl start mysqld
登录到mysql
- 5.7版本默认对于root帐号有一个随机密码,可以通过
grep "password" /var/log/mysqld.log
获得,root@localhost: 此处为随机密码 - 运行mysql -uroot -p 回车
- 粘贴随机密码
- 修改密码
- 重启
Open & Edit /etc/my.cnf
or /etc/mysql/my.cnf
, depending on your distro.
Add skip-grant-tables
under [mysqld]
Restart Mysql
service mysqld restart
You should be able to login to mysql now using the below command mysql -u root -p
Run mysql> flush privileges;
Set new password by ALTER USER 'root'@'localhost' IDENTIFIED BY 'root';
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root';
Go back to /etc/my.cnf
and remove/comment skip-grant-tables
Restart Mysql
service mysqld restart
Now you will be able to login with the new password mysql -u root -p
操作
- 默认的随机密码是没办法直接对数据库做操作的,需要修改密码,然后,5.7版本用了validate_password密码加强插件,因此在修改密码的时候绝对不是 123456 能糊弄过去的。需要严格按照规范去设置密码
- 但是,如果想让密码简单点也可以,降低安全策略, 登录到mysql客户端执行如下两条命令
set global validate_password_length=1;
set global validate_password_policy=0;
- 这样就能设置简单的密码了,但是密码长度必须是大于等于4位
赋权操作
默认情况下其他服务器的客户端不能直接访问mysql服务端,需要对ip授权
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;