分库分表

分库分表

  • 关系型数据库和NoSQL

    非关系型数据库: key-value: redis 、memcache ;

    面向文档: mongoDB

    面向列: HBase

    数据切分

    mycat

    TDDL

    Sharding-JDBC

    cobar

  1. 对于存储层的压力知道如何去提供解决方案和思路
  2. 对分库分表的常用手段有全面了解
  3. 了解Mysql的主从及binlog
  4. 知道Mycat及其他相似的中间件

为什么要分库分表

超大容量问题

  • 订单表数据量过大

    • 单表处理能力有瓶颈

性能问题

  • 单一数据库解决所有应用节点

    • 单一数据库有性能极限

如何去做到

垂直切分、 水平切分

  1. 垂直分库

    1. 解决的是表过多的问题
    2. 不同的表放在不同的库中

      1. 比如说订单相关的放在订单库中
  2. 垂直分表

    1. 解决单表列过多的问题
    2. 列多的表拆分成多个列少的表

      1. 比如说商 品表拆分

        1. 通过关联关系维持数据

水平切分

  • 大数据表拆成小表

常见的拆分策略

拆分如果全部放在一个库中,可能会有性能问题。

​ 可能把部分表放在不同的数据库中

拆分维度选择的数据非常重要

垂直拆分

​ er分片

水平拆分

  • 一致性hash
  • 范围切分

    • 可以按照ID
  • 日期拆分

拆分以后带来的问题

跨库join的问题

select a.x ,b.y from a,b on a.id=b.id

  1. 设计的时候考虑到应用层的join问题。

    1. 拆分的时候考虑好
  2. 在服务层去做调用

    A服务里查询到一个list

    直接通过接口查询

/**
    *批量查询不要这样使用
**/
for(list){
  bservice.select(list);
}
  1. 全局表

    1. 数据变更比较少的基于全局应用的表
    2. 或者抽离公共服务
  2. 做字段冗余(空间换时间的做法)

    ​ 订单表需要展示,商家id 商家名称(因为订单表和商家表是一对一的关系),那么查询的时候可能每一次都需要为了查询商家名称,可以做商家名称字段冗余

    ​ 商家名称变更解决办法

    1. 定时任务
    2. 任务通知

跨分片数据排序分页

​ 在应用层做拼接

唯一主键问题

​ 用自增id做主键,多表情况下自增id会重复

解决方案

  • UUID 性能比较低

    • 值比较长
    • 导致索引比较大
    • 性能比较低
  • snowflake (雪花算法)

    • 时间序列
    • 机器标志
    • 技术顺序号
    • 一起组成的完成id
  • mongoDB

    • ObjectId
  • zookeeper

    • 有序节点,从1开始递增
  • redis自增

    • incr
  • 数据库表

    • 专门一张表来获取id

分布式事务问题

​ 多个数据库表之间保证原子性

​ 性能问题; 互联网公司用强一致性分布式事务比较少,一般使用最终一致性,或者软事物来解决

​ 分库分表最难的在于业务的复杂度;

​ 前提: 水平分表的前提是已经存在大量的业务数据。而这个业务数据已经渗透到了各个应用节点

如何权衡当前公司的存储需要优化

1. 提前规划(主键问题解决、 join问题)

2. 当前数据单表超过1000W、每天的增长量持续上升

Mysql的主从

绝大部分都是写少读多的操作,可以做读写分离,多个读库做压力释放

读库可以实现负载均衡

分库分表_第1张图片

数据库的版本5.7版本

安装以后文件对应的目录

mysql的数据文件和二进制文件: /var/lib/mysql/

mysql的配置文件: /etc/my.cnf

mysql的日志文件: /var/log/mysql.log

6 为master

  1. 创建一个用户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

  1. 修改118 my.cnf配置文件, 在[mysqld]下增加如下配置
server-id=118  #服务器id,唯一

relay-log=slave-relay-bin #中继日志,保存master同步过来的信息

relay-log-index=slave-relay-bin.index

read_only=1
  1. 重启数据库: systemctl restart mysqld
  2. 连接到数据库客户端,通过如下命令建立同步连接
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可以找到对应的值,不能随便写。

  1. 执行 start slave
  2. show slave status\G;

    1. 查看slave服务器状态,当如下两个线程状态为yes,表示主从复制配置成功

      Slave_IO_Running=Yes
      Slave_SQL_Running=Yes

主从同步的原理

分库分表_第2张图片

  1. master记录二进制日志。在每个事务更新数据完成之前,master在二日志记录这些改变。MySQL将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master通知存储引擎提交事务

    1. slave将master的binary log拷贝到它自己的中继日志。首先,slave开始一个工作线程——I/O线程。I/O线程在master上打开一个普通的连接,然后开始binlog dump process。Binlog dump process从master的二进制日志中读取事件,如果已经跟上master,它会睡眠并等待master产生新的事件。I/O线程将这些事件写入中继日志
    2. 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'

主从同步的延时问题

在这里插入图片描述
一主多从或者双主

网络延迟比较大

磁盘的读写

主从同步延迟是怎么产生的

  1. 当master库tps比较高的时候,产生的DDL数量超过slave一个sql线程所能承受的范围,或者slave的大型query语句产生锁等待
  2. 网络传输: bin文件的传输延迟
  3. 磁盘的读写耗时:文件通知更新、磁盘读取延迟、磁盘写入延迟

解决方案

  1. 在数据库和应用层增加缓存处理,优先从缓存中读取数据

    1. 从缓存中取,同步后然后再从slave中取
  2. 减少slave同步延迟,可以修改slave库sync_binlog属性;

    sync_binlog=0 设置为0执行ddl binlog不会立马刷新到文件中,而是通过文件系统调度刷新

    ​ 文件系统来调度把binlog_cache刷新到磁盘

sync_binlog=n 等于n表示执行n个事物刷新

  1. 增加延时监控

    Nagios做网络监控

    mk-heartbeat 心跳监控

    通过监控做报警

  2. Mysql的主从配置
  3. 了解binlog及主从复制原理

MyCat

简介

地址:http://www.mycat.io/

​ https://github.com/MyCATApach...

​ 相当于代理

分库分表_第3张图片

作用

  • 拦截sql
  • 分片
  • 路由
  • 缓存
  • 读写分离

查询如果是分片键那么直接落到对应数据库,如果不是分片键,那么会路由到所有数据库

haproxy负载均衡

keepalive 高可用

配置文件

rlue.xml

​ 分片数据库

分库分表_第4张图片
image-20190508120117289

对应的rule分片策略

范围分片

分库分表_第5张图片
这是范围分片,0-200M表示到分片5

schema.xml

​ 逻辑数据库逻辑表

server.xml

​ 配置当前服务

使用

单库大表拆分

分库分表_第6张图片

跨库分表

分库分表_第7张图片

读写分离

分库分表_第8张图片

高可用

分库分表_第9张图片

分库分表双主(数据双向同步)策略

分库分表_第10张图片

  • 需要通过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

  1. 5.7版本默认对于root帐号有一个随机密码,可以通过 grep "password" /var/log/mysqld.log获得,root@localhost: 此处为随机密码
  2. 运行mysql -uroot -p 回车
  3. 粘贴随机密码
  4. 修改密码
  5. 重启

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

操作

  1. 默认的随机密码是没办法直接对数据库做操作的,需要修改密码,然后,5.7版本用了validate_password密码加强插件,因此在修改密码的时候绝对不是 123456 能糊弄过去的。需要严格按照规范去设置密码
  2. 但是,如果想让密码简单点也可以,降低安全策略, 登录到mysql客户端执行如下两条命令
set global validate_password_length=1;

set global validate_password_policy=0; 
  1. 这样就能设置简单的密码了,但是密码长度必须是大于等于4位

赋权操作

默认情况下其他服务器的客户端不能直接访问mysql服务端,需要对ip授权
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;

你可能感兴趣的:(mycat,分库分表)