集群的知识架构

# 集群的知识架构 ## 为什么需要集群?或者说集群的目的是什么? - **高可用**: 通俗点来说, 如果目标应用需要访问MySQL获取数据, 当这个MySQL因故宕机之后, 对这个应用毫无影响, 这被称为高可用 - 要想实现高可用, 必须通过集群, 否则, 若只有一台MySQL, 当他宕机的时候, 整个功能都不可用, 造成单点故障 - **突破数据量限制**: 通俗点来说, 本来整个服务最多能存储100w条数据, 现在能存储1kw条数据, 即突破数量限制 - 如果要实现突破数量限制, 依旧离不开集群, 在集群情况下, 可以做分片存储, 即每一个节点都存储一点, 如果在单机模式下, 存储容量有限, 不可能比分片存储的存储能力强 - **数据备份容灾**: 最简单的场景下, 如果一个MySQL的数据被误删了, 在集群模式下可以通过其他节点的数据备份来恢复数据, 在单机模式下, 数据丢失, 还有更多数据丢失的场景... - **压力分担**: 通俗点来说, 一共有100w的请求, 在集群模式下每一个节点共同分担这100w, 相较于单机模式的独立承担, 压力更小, 容错更强, 不易宕机 ## 集群的存储形式 ![image.png](https://cos.easydoc.net/13568421/files/ln34roqj.png) > 特别说明: K8S是基于主从式的, 采用主从调度, 它不具有选主的能力, 因此, K8S的主节点需要构造一个集群 ## 构建MySQL集群 ### MMM模式 ![image.png](https://cos.easydoc.net/13568421/files/ln35dfrc.png) *MySQL-MMM 是 Master-Master Replication Manager for MySQL(mysql 主主复制管理器)的简称,是 Google 的开源项目(Perl 脚本)。MMM 基于 MySQL Replication 做的扩展架构,主要用来监控 mysql 主主复制并做失败转 移。其原理是将真实数据库节点的IP(RIP)映射为虚拟 IP(VIP)集。mysql-mmm 的监管端会提供多个虚拟 IP(VIP),包括一个可写 VIP,多个可读 VIP,通过监管的管理,这些 IP 会绑定在可用 mysql 之上,当某一台 mysql 宕机时,监管会将 VIP迁移至其他 mysql。在整个监管过程中,需要在 mysql 中添加相关授权用户,以便让 mysql 可以支持监理机的维护。授权的用户包括一个mmm_monitor 用户和一个 mmm_agent 用户,如果想使用 mmm 的备份工具则还要添加一个 mmm_tools 用户。* #### MMM模式的原理 > **MMM模式主要是靠虚拟IP集来实现服务的高可用的, 类似于NGINX的高可用** > 虚拟IP集一共有两大类, 一个是可读虚拟IP, 一个可写虚拟IP, 由上面的图可知, 这里有两个主节点, 实际上, **整个集群只能有一个主节点, 那么另外一个主节点自动降为从节点, 主节点和从节点进行主从复制** > 虚拟IP会自动将读写分离, 读操作通过可读的虚拟IP访问从节点, 写操作通过可写虚拟IP访问主节点 > **当一个主节点宕机的时候, 另一个主节点(当前为从节点)自动晋升为主节点, 写操作的虚拟IP自动漂移到新的主节点中, 以前的主节点容灾恢复后, 自动降为从节点** ### <font color="red">InnoDBCluster模式</font> ![image.png](https://cos.easydoc.net/13568421/files/ln35nsn9.png) *InnoDB Cluster 支持自动 Failover、强一致性、读写分离、读库高可用、读请求负载均衡,横向扩展的特性,是比较完备的一套方案。但是部署起来复杂,想要解决 router单点问题好需要新增组件,如没有其他更好的方案可考虑该方案。 InnoDB Cluster 主要由 MySQL Shell、MySQL Router 和 MySQL 服务器集群组成,三者协同工作,共同为MySQL 提供完整的高可用性解决方案。MySQL Shell 对管理人员提供管理接口,可以很方便的对集群进行配置和管理,MySQL Router 可以根据部署的集群状况自动的初始化,是客户端连接实例。如果有节点 down 机,集群会自动更新配置。集群包含单点写入和多点写入两种模式。在单主模式下,如果主节点 down 掉,从节点自动替换上来,MySQL Router 会自动探测,并将客户端连接到新节点* #### InnoDBCluster模式的原理 > **首先, 明确的是, 主节点和从节点之间是遵顼主从复制的, 除了遵循主从复制, 主节点可以进行读写操作, 而从节点是制度操作** > 整体的工作流程是, 客户端发送请求的时候, 无论是什么请求, 都不直接访问节点(无论是主节点还是从节点), 而是访问代理服务器, 通过代理服务器将请求分发, 不同的请求分发到不同的节点 > **如果从节点down掉了, 路由会重新分配主从, 将从节点晋升为主节点** ### 总结 #### 共同点 1. **它们都是主从复制的** 2. **读写分离** ### 企业实战的原理 ![image.png](https://cos.easydoc.net/13568421/files/ln35yl6f.png) 1. 所有的数据库请求都不访问任何一个节点, 只访问代理服务器, 由代理服务器分发请求, 实现读写分离 2. 这里有两个主节点, 主要是为了防止主节点崩溃, 这样的好处是, 如果主节点没问题, 备份主节点主要和主节点做主从同步, 如果主节点宕机了, 备份主节点立刻补位, 实现了高可用 3. 这里有很多从节点, 从节点实现了场景划分, 即从库服务的对象实现了划分, 有些是专门做备份的, 有些给后端管理系统的, 有些给用户服务的, 这样最大力度减小了数据库服务压力 ### 为什么要分库分表 [MySQL数据量与CURD效率的关系图](https://www.processon.com/embed/651576b4ee3af44dd46b0efa) > 我们从这个图可知, 当数据量越大, 他的各项性能都下降的非常厉害, 所以, 我们不能让一个数据库的表承担过大的数据量, 所以, 我们不得不分库分表, 从而提高效率 > 如果进行了分库分表, 从这个关系图可以看出, 效率会高很多 ### 主从复制的原理 > 主节点的任何写操作都会被记录到一个binlong日志里面, 从节点通过读取binlong日志, 从而一比一还原主节点的操作, 从而在从节点上操作, 获取和主节点一样的数据, 从而实现主从同步 ## 构建MySQL集群 ![image.png](https://cos.easydoc.net/13568421/files/ln394g0v.png) ![image.png](https://cos.easydoc.net/13568421/files/ln394s9o.png) ![image.png](https://cos.easydoc.net/13568421/files/ln3atgwn.png) ``` [client] default-character-set=utf8mb4 [mysql] default-character-set=utf8mb4 [mysqld] init_connect='SET collation_connection = utf8mb4_unicode_ci' init_connect='SET NAMES utf8mb4' character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci skip-character-set-client-handshake skip-name-resolve server_id=1 #[每一个都不一样] log-bin=mysql-bin read-only=0 #[从节点是1] binlog-do-db=btimall_ums binlog-do-db=bitmall_pms binlog-do-db=bitmall_oms binlog-do-db=bitmall_sms binlog-do-db=bitmall_wms binlog-do-db=bitmall_admin replicate-ignore-db=mysql replicate-ignore-db=sys replicate-ignore-db=information_schema replicate-ignore-db=performance_schema ``` ### 主节点配置 ![image.png](https://cos.easydoc.net/13568421/files/ln3792wj.png) ![image.png](https://cos.easydoc.net/13568421/files/ln38mgip.png) ![image.png](https://cos.easydoc.net/13568421/files/ln37tl3r.png) ![image.png](https://cos.easydoc.net/13568421/files/ln3ab4bw.png) ![image.png](https://cos.easydoc.net/13568421/files/ln3al6kt.png) ![image.png](https://cos.easydoc.net/13568421/files/ln37ykfp.png) --- #### 坑 ##### 关于创建PVC的坑 > <font color="red">**访问模式必须是ReadWriteOnce**</font>, 如果是**ReadWriteMany**, 就会发生无法调度容器的错误 ##### 挂载配置文件的坑 > 理论上来说, 我们挂载的目录是`/etc/mysql`, 然后对`my.cnf`这个配置继续挂载到`my.cnf`, 但是, 这样MySQL启动会报错, 说找不到`conf.d`目录, 因此, 我们挂载的目录改成图片所示的`/etc/mysql/conf.d` ##### 关于配置文件的坑 ```cnf [client] default-character-set=utf8 [mysql] default-character-set=utf8 [mysqld] init_connect='SET collation_connection = utf8_unicode_ci' init_connect='SET NAMES utf8' character-set-server=utf8 collation-server=utf8_unicode_ci skip-character-set-client-handshake skip-name-resolve ``` > 这是老师给的配置文件, 这个配置文件的字符编码设置有问题, 会导致容器重启, 需要改成下面的 ```cnf [client] default-character-set=utf8mb4 [mysql] default-character-set=utf8mb4 [mysqld] init_connect='SET collation_connection = utf8mb4_unicode_ci' init_connect='SET NAMES utf8mb4' character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci skip-character-set-client-handshake skip-name-resolve ``` ### 从节点配置 > **这里PVC的创建方式和主节点的一模一样, 配置文件也大致一样, 只有服务器id(递增)和 只读配置(1)需要改变** > **其他配置和主节点一模一样** ### 授权用户 1. 通过kubeSphere进入MySQL容器, 先登录 2. 授权root用户 ```sql grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option; flush privileges; ``` 3. 添加同步用户 ```sql GRANT REPLICATION SLAVE ON *.* to 'backup'@'%' identified by '123456'; ``` 4. 查看主节点状态(记住File的值) ```sql show master status\G; ``` ### 配置从节点同步主节点 1. 授权root用户 ```sql grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option; flush privileges; ``` 2. 连接主节点 ```sql change master to master_host='mysql-master.bitmall',master_user='backup',master_password='123456',master_log_file='mysql-bin.000005',master_log_pos=0,master_port=3306; ``` > `master_host`是kubesphere提供给pod的域名, 在pod那里查找就行了 > `master-password`必须是backup的密码, 否则有一个状态会一直处于connecting状态 > `master_log_file`通过查看主节点状态得知 > 后面的是固定的 3. 启动从库同步 ```sql start slave; ``` 4. 查看状态 ```sql show slave status\G; ``` 设置错了可以执行下面的指令重置从节点, 从节点的配置是一模一样的 ```sql stop slave; reset slave all; ``` ![image.png](https://cos.easydoc.net/13568421/files/ln3y42c0.png) ### 将MySQL的节点都以端口的形式暴露出现(全部操作都一样) ![image.png](https://cos.easydoc.net/13568421/files/ln3yi9fr.png) ![image.png](https://cos.easydoc.net/13568421/files/ln3yiwxb.png) ![image.png](https://cos.easydoc.net/13568421/files/ln3yjeu2.png) ![image.png](https://cos.easydoc.net/13568421/files/ln3yjtpt.png) ![image.png](https://cos.easydoc.net/13568421/files/ln3ymi5x.png) > 这里的服务端口号是pod暴露给service的, 集群pod很可能在同一个节点内, 为了避免端口冲突, 设置每一个端口都不同, 并不是外部访问的端口(NodePort) ### Navcicat连接并测试主从同步 #### 创建一个可供远程访问的超级管理员用户 ```sql GRANT ALL PRIVILEGES ON *.* TO 'remote'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION; ``` > **这里我不测试了, 我这里的主从复制没有任何的问题** ## ShardingShpere ### 为什么要用ShardingShpere? > 如果我们想要分库分表, 传统来说, 我们可以根据id的奇偶性手动选择不同的数据库不同的表进行连接, 这种方案确实可行, 但是, 就现实意义来说, 太麻烦了, , 而且某个节点宕机了, 很可能导致某个数据丢失, 所以, 不用这种 > 为了解决分库分表的痛点, ShardingShpere能提供一系列的解决方案, 因此, ShardingShpere用于分库分表, 读写分离非常的方便 ### 介绍 [**官方概览**](https://shardingsphere.apache.org/document/current/cn/overview/) > 总结: ShardingProxy和ShardingJDBC最大的区别是, 一个需要访问代理对象, 由代理对象通过分库分表, 读写分离, 一个直接访问数据库, 不需要经过代理对象 > **最终我们采用ShardingProxy, 有中心更加契合我们的代码** ### 架构(如果不想像我一样配置, 可以直接下载我的镜像) #### 下载ShardingSphere-Proxy [下载4.1.0版本](https://archive.apache.org/dist/shardingsphere/) #### 配置文件 ![image.png](https://cos.easydoc.net/13568421/files/ln4oss7h.png) ![image.png](https://cos.easydoc.net/13568421/files/ln4oymef.png) ![image.png](https://cos.easydoc.net/13568421/files/ln4ozeev.png) #### 启动Bug修复 1. 找不到server.yaml : 是因为没有放在纯英文目录下, 而且不能有空格 2. root用户远程连接问题: 这是因为本地的root@localhost影响了, 创建一个远程超级管理员用户就可以了 3. 没有数据库异常: ShardingSphere不会帮助我们创建数据库, 所以我们要自己在主节点中创建数据库 4. **navicat15连接shardingsphere-proxy报1064错误: 改成navicat11就好了** 5. 插入不了数据: 这里是因为我们分库分表策略用到了%, 这要求数据类型必须是int, 如果是varchar就会报错 6. 插入不了数据: 还有一种情况显示什么GROUPBY的, 这个不用管, 不影响, 是navicat的错误而已 ## 分库分表的所有配置 ### 1. 生成SQL的脚本文件 ![image.png](https://cos.easydoc.net/13568421/files/ln5bd9sk.png) ### 2. 配置文件 ![image.png](https://cos.easydoc.net/13568421/files/ln5cmpp1.png) > 注意: 这个版本的navicat有问题, 他对表长限制了, 实际上是没有问题的, 我们不管就行了 ### 3. 创建对应的数据库和数据表 ![image.png](https://cos.easydoc.net/13568421/files/ln6214tz.png) ### 4. 改成域名访问形式 > 把里面的ip地址全部改成域名就行 ### 5. 创建镜像 ```dockerfile docker build -t [镜像名字, 按照阿里云] -f Dockerfile . ``` ```dockerfile # 基于centos镜像 FROM apache/sharding-proxy:4.1.0 # 添加作者 LABEL org.opencontainers.image.authors="江骏杰" ADD conf.tar.gz /opt/sharding-proxy/ ADD mysql-connector-java-5.1.49.jar /opt/sharding-proxy/ext-lib # 暴露端口号 EXPOSE 3307 ``` ### 第一个大坑 #### 是否支持多个config-sharding.yaml #### 主从同步问题 > 因为我配置文件写错了, 所以无法主从同步bitmall_ums(配置文件写成了btimall_ums) > 我们可以先改config_map里面的数据, 然后删除容器, 再执行以下指令即可 ```shell stop slave; set GLOBAL SQL_SLAVE_SKIP_COUNTER=1; start slave; ``` ### 镜像地址 > 不想搞这么多, 直接拉我的镜像, 改改里面的某个配置就行 ```shell docker pull registry.cn-hangzhou.aliyuncs.com/junjie-joelib/junjie-shardingsphere-proxy ``` ### kubeSphere设置镜像仓库并部署 [教程](https://v3-1.docs.kubesphere.io/zh/docs/project-user-guide/configuration/image-registry/) ![image.png](https://cos.easydoc.net/13568421/files/ln64q1ec.png) ![image.png](https://cos.easydoc.net/13568421/files/ln64r0s7.png) // 连接问题 -> 画图 -> 部署 -> 测试 ### 相关知识点 #### 为什么不可以用自增主键? > 因为ShardingSphere-Proxy可以理解为一个逻辑数据库管理系统, 里面有逻辑数据库和逻辑表, 就以逻辑表为例, 当我们往这些表插入数据的时候, 实际上是往分库分表的目的MySQL里面插入, 如果用自增主键, 分表的情况下, 逻辑表会出现两个主键相同的数据, 不符合逻辑, 因此, 不能用自增主键 > 我们建议使用雪花算法生成主键, 而且主键建议只用BIGINT类型, 便于分库分表 #### 为什么分库分表策略要一样? > 这里说的比较笼统, 具体的指的是两个具有关联关系的表, 它们的分库分表策略要一样, 比如说订单表和订单详情表, 它们都要以订单号作为分库分表策略, 这里主要有两个原因 > 1. 因为它们有关联关系, 所以为了逻辑上的合法性, 因此策略要一样 > 2. 因为它们有关联关系, 如果策略一样就会分配到同一个数据库上, 关联查询更快, 不需要跨数据源