MySQL到底能支持多大的数据量
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL到底能支持多大的数据量相关的知识,希望对你有一定的参考价值。
mysql 3.22 限制的表大小为4GB。由于在MySQL 3.23 中使用了MyISAM 存储引擎,最大表尺寸增加到了65536TB(2567 – 1字节)。由于允许的表尺寸更大,MySQL数据库的最大有效表尺寸通常是由操作系统对文件大小的限制决定的,而不是由MySQL内部限制决定的。
InnoDB 存储引擎将InnoDB 表保存在一个表空间内,该表空间可由数个文件创建。这样,表的大小就能超过单独文件的最大容量。表空间可包括原始磁盘分区,从而使得很大的表成为可能。表空间的最大容量为64TB。
扩展资料
MySQL数据库中,数据量越来越大的优化方案:
单表优化可以从这几个角度出发:
1、表分区
MySQL在5.1之后才有的,可以看做是水平拆分,分区表需要在建表的需要加上分区参数,用户需要在建表的时候加上分区参数;分区表底层由多个物理子表组成,但是对于代码来说,分区表是透明的。
SQL中的条件中最好能带上分区条件的列,这样可以定位到少量的分区上,否则就会扫描全部分区。
2、增加缓存
主要的思想就是减少对数据库的访问,缓存可以在整个架构中的很多地方;比如:数据库本身有就缓存,客户端缓存,数据库访问层对SQL语句的缓存,应用程序内的缓存,第三方缓存(如Redis等)。
参考技术A非root用户运行MySQL,当MySQL配置比较高时,MySQL运行中生效的参数值与配置的值不一样,所以具体分析一下MySQL是怎么调整这些参数值的。 这篇文章的目的是为了说明在系统资源不够的情况下,MySQL 是怎么调整者三个参数的。说明此文涉及到三个参数open_files_limit、 max_connections、 table_open_cache。与这三个参数相关的系统资源是打开文件数限制,即文件描述符(fd)限制。系统参数与文件描述符的关系 - max_connection & fd : 每一个MySQL connection 都需要一个文件描述符;- table_open_cache & fd 打开一张表至少需要一个 文件描述符,如打开MyISAM需要两个fd ;- 系统最大打开文件数可以通过 ulimit -n查看。MySQL调整参数的方式
根据配置(三个参数的配置值或默认值)计算 request_open_files(需要的文件描述符);
2.获取有效的系统的限制值effective_open_files; 3.根据effective_open_files调整request_open_files; 4.根据调整后的request_open_files,计算实际生效的参数值(show variables 可查看参数值)。计算request_open_filesrequest_open_files有三个计算公式:1. // 最大连接数+同时打开的表的最大数量+其他(各种日志等等)2. limit_1= max_connections+table_cache_size * 2 + 10;3. 4. //假设平均每个连接打开的表的数量(2-4)5. //源码中是这么写的:6. //We are trying to allocate no less than 7. // max_connections*5 file handles8. limit_2= max_connections * 5;9. 10. //mysql 默认的默认是500011. limit_3= open_files_limit ? open_files_limit : 5000;12. 13. 所以open_files_limit期待的最低14. request_open_files= max(limit_1,limit_2,limit_3);计算effective_open_files:MySQL 的思路:
在有限值的的范围内MySQL 尽量将effective_open_files的值设大。
修正request_open_files
requested_open_files= min(effective_open_files, request_open_files)
重新计算参数值
修正open_files_limit
open_files_limit = effective_open_files
修正max_connections
max_connections 根据 request_open_files 来做修正。1. limit = requested_open_files - 10 - TABLE_OPEN_CACHE_MIN * 2;
如果配置的max_connections值大于limit,则将max_connections 的值修正为limit
其他情况下 max_connections 保留配置值
修正table_cache_size
table_cache_size 会根据 request_open_files 来做修正1. // mysql table_cache_size 最小值,4002. limit1 = TABLE_OPEN_CACHE_MIN3. // 根据 requested_open_files 计算4. limit2 = (requested_open_files - 10 - max_connections) / 25. limit = max(limit1,limt2);
如果配置的table_cache_size 值大于limit,则将 table_cache_size 的值修正为limit
其他情况下table_cache_size 保留配置值
举例
以下用例在非 root 用户下运行
参数设置:
//mysql
max_connections = 500
table_open_cache = 999
//ulimit -n
1500
生效的值:
open_files_limit = 1500 max_connections = min[(1500 - 10 - 800),500] = 500
table_open_cache = ( 1500 - 10 - 500) / 2 =495
1、从MySQL 3.23开始,MySQL单表最大限制就已经扩大到了64PB了(官方文档显示)。也就是说,从目前的技术环境来看,MySQL数据库的MyISAM存储 引擎单表大小限制已经不是有MySQL数据库本身来决定,而是由所在主机的OS上面的文件系统来决定了。
2、没有人会那么去存数据的,因为查询速度太慢了,这时候就分表了,比如垂直分割,水平分割等等本回答被提问者和网友采纳 参考技术C 1.最简单的方法:
public static String reverse1(String str)
return new StringBuffer(str).reverse().toString();
2.最常用的方法:
public static String reverse3(String s)
char[] array = s.toCharArray();
String reverse = ""; //注意这是空,不是null
for (int i = array.length - 1; i >= 0; i--)
reverse += array[i];
return reverse;
3.常用方法的变形:
public static String reverse2(String s)
int length = s.length();
String reverse = ""; //注意这是空,不是null
for (int i = 0; i < length; i++)
reverse = s.charAt(i) + reverse;//在字符前面连接, 而非常见的后面
return reverse;
Redis高可用篇:Cluster集群能支持的数据量有多大?
码哥出品,必属精品。关注公众号「码哥字节」并加码哥微信(MageByte1024),窥探硬核文章背后的男人的另一面。
本文将对集群的节点、槽指派、命令执行、重新分片、转向、故障转移、消息等各个方面进行深入拆解。
目的在于掌握什么是 Cluster ?Cluster 分片原理,客户端定位数据原理、故障切换,选主,什么场景使用 Cluster,如何部署集群 …...
[toc]
为什么需要 Cluster
主要是 Redis RDB 持久化机制导致的,Redis 会 Fork 子进程完成 RDB 持久化操作,fork 执行的耗时与 Redis 数据量成正相关。
而 Fork 执行的时候会阻塞主线程,由于数据量过大导致阻塞主线程过长,所以出现了 Redis 响应慢的表象。
保存大量数据,除了使用大内存主机的方式,我们还可以使用切片集群。俗话说「众人拾材火焰高」,一台机器无法保存所有数据,那就多台分担。
使用 Redis Cluster 集群,主要解决了大数据量存储导致的各种慢问题,同时也便于横向拓展。
两种方案对应着 Redis 数据增多的两种拓展方案:垂直扩展(scale up)、水平扩展(scale out)。
- 垂直拓展:升级单个 Redis 的硬件配置,比如增加内存容量、磁盘容量、使用更强大的 CPU。
- 水平拓展:横向增加 Redis 实例个数,每个节点负责一部分数据。
比如需要一个内存 24 GB 磁盘 150 GB 的服务器资源,有以下两种方案:
在面向百万、千万级别的用户规模时,横向扩展的 Redis 切片集群会是一个非常好的选择。
- 垂直拓展部署简单,但是当数据量大并且使用 RDB 实现持久化,会造成阻塞导致响应慢。另外受限于硬件和成本,拓展内存的成本太大,比如拓展到 1T 内存。
- 水平拓展便于拓展,同时不需要担心单个实例的硬件和成本的限制。但是,切片集群会涉及多个实例的分布式管理问题,需要解决如何将数据合理分布到不同实例,同时还要让客户端能正确访问到实例上的数据。
什么是 Cluster 集群
Redis 集群是一种分布式数据库方案,集群通过分片(sharding)来进行数据管理(「分治思想」的一种实践),并提供复制和故障转移功能。
将数据划分为 16384 的 slots,每个节点负责一部分槽位。槽位的信息存储于每个节点中。
它是去中心化的,如图所示,该集群有三个 Redis 节点组成,每个节点负责整个集群的一部分数据,每个节点负责的数据多少可能不一样。
三个节点相互连接组成一个对等的集群,它们之间通过 Gossip
协议相互交互集群信息,最后每个节点都保存着其他节点的 slots 分配情况。
开篇寄语
集群安装
一个 Redis 集群通常由多个节点(node)组成,在刚开始的时候,每个节点都是相互独立的,它们都处于一个只包含自己的集群当中,要组建一个真正可工作的集群,我们必须将各个独立的节点连接起来,构成一个包含多个节点的集群。
连接各个节点的工作可以通过 CLUSTER MEET
命令完成:CLUSTER MEET <ip> <port>
。
向一个节点 node 发送 CLUSTER MEET
命令,可以让 node 节点与 ip 和 port 所指定的节点进行握手(handshake),当握手成功时,node 节点就会将 ip 和 port 所指定的节点添加到 node 节点当前所在的集群中。
就好像 node 节点说:“喂,ip = xx,port = xx 的老哥,要不要加入「码哥字节」技术群,加入集群就找到了一条大神成长之路,关注「码哥字节」公众号回复「加群」,是兄弟就跟我一起来!”
关于 Redis Cluster 集群搭建详细步骤,请点击文末左下角「阅读原文」或者点击 -> 《Redis 6.X Cluster 集群搭建》查看,官方关于 Redis Cluster 的详情请看:https://redis.io/topics/cluster-tutorial。
Cluster 实现原理
Redis 3.0 开始,官方提供了 Redis Cluster 方案实现了切片集群,该方案就实现了数据和实例的规则。Redis Cluster 方案采用哈希槽(Hash Slot,接下来我会直接称之为 Slot),来处理数据和实例之间的映射关系。
跟着「码哥字节」一起进入 Cluster 实现原理探索之旅…...
将数据分成多份存在不同实例上
集群的整个数据库被分为 16384 个槽(slot),数据库中的每个键都属于这 16384 个槽的其中一个,集群中的每个节点可以处理 0 个或最多 16384 个槽。
Key 与哈希槽映射过程可以分为两大步骤:
- 根据键值对的 key,使用 CRC16 算法,计算出一个 16 bit 的值;
- 将 16 bit 的值对 16384 执行取模,得到 0 ~ 16383 的数表示 key 对应的哈希槽。
Cluster 还允许用户强制某个 key 挂在特定槽位上,通过在 key 字符串里面嵌入 tag 标记,这就可以强制 key 所挂在的槽位等于 tag 所在的槽位。
哈希槽与 Redis 实例映射
在 部署集群的样例中通过 cluster create
创建,Redis 会自动将 16384 个 哈希槽平均分布在集群实例上,比如 N 个节点,每个节点上的哈希槽数 = 16384 / N 个。
除此之外,可以通过 CLUSTER MEET
命令将 7000、7001、7002 三个节点连在一个集群,但是集群目前依然处于下线状态,因为三个实例都没有处理任何哈希槽。
可以使用 cluster addslots
命令,指定每个实例上的哈希槽个数。
能者多劳嘛,加入集群中的 Redis 实例配置不一样,如果承担一样的压力,对于垃圾机器来说就太难了,让牛逼的机器多支持一点。
三个实例的集群,通过下面的指令为每个实例分配哈希槽:实例 1
负责 0 ~ 5460 哈希槽,实例 2
负责 5461~10922 哈希槽,实例 3
负责 10923 ~ 16383 哈希槽。
redis-cli -h 172.16.19.1 –p 6379 cluster addslots 0,5460
redis-cli -h 172.16.19.2 –p 6379 cluster addslots 5461,10922
redis-cli -h 172.16.19.3 –p 6379 cluster addslots 10923,16383
键值对数据、哈希槽、Redis 实例之间的映射关系如下:
Redis 键值对的 key 「码哥字节」「牛逼」经过 CRC16 计算后再对哈希槽总个数 16394 取模,模数结果分别映射到实例 1 与实例 2 上。
切记,当 16384 个槽都分配完全,Redis 集群才能正常工作。
复制与故障转移
Master 用于处理槽,Slave 节点则通过《Redis 主从架构数据同步》方式同步主节点数据。
当 Master 下线,Slave 代替主节点继续处理请求。主从节点之间并没有读写分离, Slave 只用作 Master 宕机的高可用备份。
Redis Cluster 可以为每个主节点设置若干个从节点,单主节点故障时,集群会自动将其中某个从节点提升为主节点。
如果某个主节点没有从节点,那么当它发生故障时,集群将完全处于不可用状态。
不过 Redis 也提供了一个参数cluster-require-full-coverage
可以允许部分节点故障,其它节点还可以继续提供对外访问。
比如 7000 主节点宕机,作为 slave 的 7003 成为 Master 节点继续提供服务。当下线的节点 7000 重新上线,它将成为当前 70003 的从节点。
故障检测
一个节点认为某个节点失联了并不代表所有的节点都认为它失联了。只有当大多数负责处理 slot 节点都认定了某个节点下线了,集群才认为该节点需要进行主从切换。
Redis 集群节点采用 Gossip
协议来广播自己的状态以及自己对整个集群认知的改变。比如一个节点发现某个节点失联了 (PFail),它会将这条信息向整个集群广播,其它节点也就可以收到这点失联信息。
如果一个节点收到了某个节点失联的数量 (PFail Count) 已经达到了集群的大多数,就可以标记该节点为确定下线状态 (Fail),然后向整个集群广播,强迫其它节点也接收该节点已经下线的事实,并立即对该失联节点进行主从切换。
故障转移
当一个 Slave 发现自己的主节点进入已下线状态后,从节点将开始对下线的主节点进行故障转移。
- 从下线的 Master 及节点的 Slave 节点列表选择一个节点成为新主节点。
- 新主节点会撤销所有对已下线主节点的 slot 指派,并将这些 slots 指派给自己。
- 新的主节点向集群广播一条 PONG 消息,这条 PONG 消息可以让集群中的其他节点立即知道这个节点已经由从节点变成了主节点,并且这个主节点已经接管了原本由已下线节点负责处理的槽。
- 新的主节点开始接收处理槽有关的命令请求,故障转移完成。
选主流程
- 集群的配置纪元 +1,是一个自曾计数器,初始值 0 ,每次执行故障转移都会 +1。
- 检测到主节点下线的从节点向集群广播一条
CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST
消息,要求所有收到这条消息、并且具有投票权的主节点向这个从节点投票。 - 这个主节点尚未投票给其他从节点,那么主节点将向要求投票的从节点返回一条
CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK
消息,表示这个主节点支持从节点成为新的主节点。 - 参与选举的从节点都会接收
CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK
消息,如果收集到的票 >= (N/2) + 1 支持,那么这个从节点就被选举为新主节点。 - 如果在一个配置纪元里面没有从节点能收集到足够多的支持票,那么集群进入一个新的配置纪元,并再次进行选举,直到选出新的主节点为止。
跟哨兵类似,两者都是基于 Raft 算法来实现的,流程如图所示:
用表保存键值对和实例的关联关系可行么
使用一个全局表记录的话,假如键值对和实例之间的关系改变(重新分片、实例增减),需要修改表。如果是单线程操作,所有操作都要串行,性能太慢。
多线程的话,就涉及到加锁,另外,如果键值对数据量非常大,保存键值对与实例关系的表数据所需要的存储空间也会很大。
而哈希槽计算,虽然也要记录哈希槽与实例时间的关系,但是哈希槽的数量少得多,只有 16384 个,开销很小。
客户端如何定位数据所在实例
Redis 实例会将自己的哈希槽信息通过 Gossip 协议发送给集群中其他的实例,实现了哈希槽分配信息的扩散。
这样,集群中的每个实例都有所有哈希槽与实例之间的映射关系信息。
在切片数据的时候是将 key 通过 CRC16 计算出一个值再对 16384 取模得到对应的 Slot,这个计算任务可以在客户端上执行发送请求的时候执行。
但是,定位到槽以后还需要进一步定位到该 Slot 所在 Redis 实例。
当客户端连接任何一个实例,实例就将哈希槽与实例的映射关系响应给客户端,客户端就会将哈希槽与实例映射信息缓存在本地。
当客户端请求时,会计算出键所对应的哈希槽,在通过本地缓存的哈希槽实例映射信息定位到数据所在实例上,再将请求发送给对应的实例。
重新分配哈希槽
集群中的实例通过 Gossip 协议互相传递消息获取最新的哈希槽分配信息,但是,客户端无法感知。
Redis Cluster 提供了重定向机制:客户端将请求发送到实例上,这个实例没有相应的数据,该 Redis 实例会告诉客户端将请求发送到其他的实例上。
分为两种情况:MOVED 错误、ASK 错误。
MOVED 错误
MOVED 错误(负载均衡,数据已经迁移到其他实例上):当客户端将一个键值对操作请求发送给某个实例,而这个键所在的槽并非由自己负责的时候,该实例会返回一个 MOVED 错误指引转向正在负责该槽的节点。
GET 公众号:码哥字节
(error) MOVED 16330 172.17.18.2:6379
该响应表示客户端请求的键值对所在的哈希槽 16330 迁移到了 172.17.18.2 这个实例上,端口是 6379。这样客户端就与 172.17.18.2:6379 建立连接,并发送 GET 请求。
同时,客户端还会更新本地缓存,将该 slot 与 Redis 实例对应关系更新正确。
ASK 错误
如果请求的 key 在当前节点找到就直接执行命令,否则时候就需要 ASK 错误响应了,槽部分迁移未完成的情况下,如果需要访问的 key 所在 Slot 正在从从 实例 1 迁移到 实例 2,实例 1 会返回客户端一条 ASK 报错信息:客户端请求的 key 所在的哈希槽正在迁移到实例 2 上,你先给实例 2 发送一个 ASKING 命令,接着发发送操作命令。
GET 公众号:码哥字节
(error) ASK 16330 172.17.18.2:6379
比如客户端请求定位到 key = 「公众号:码哥字节」的槽 16330 在实例 172.17.18.1 上,节点 1 如果找得到就直接执行命令,否则响应 ASK 错误信息,并指引客户端转向正在迁移的目标节点 172.17.18.2。
注意:ASK 错误指令并不会更新客户端缓存的哈希槽分配信息。
所以客户端再次请求 Slot 16330 的数据,还是会先给 172.17.18.1
实例发送请求,只不过节点会响应 ASK 命令让客户端给新实例发送一次请求。
MOVED
指令则更新客户端本地缓存,让后续指令都发往新实例。
集群可以设置多大?
答案是否定的,Redis 官方给的 Redis Cluster 的规模上线是 1000 个实例。
关键在于实例间的通信开销,Cluster 集群中的每个实例都保存所有哈希槽与实例对应关系信息(Slot 映射到节点的表),以及自身的状态信息。
在集群之间每个实例通过 Gossip
协议传播节点的数据,Gossip
协议工作原理大概如下:
- 从集群中随机选择一些实例按照一定的频率发送
PING
消息发送给挑选出来的实例,用于检测实例状态以及交换彼此的信息。PING
消息中封装了发送者自身的状态信息、部分其他实例的状态信息、Slot 与实例映射表信息。 - 实例接收到
PING
消息后,响应PONG
消息,消息包含的信息跟PING
消息一样。
集群之间通过 Gossip
协议可以在一段时间之后每个实例都能获取其他所有实例的状态信息。
所以在有新节点加入,节点故障,Slot 映射变更都可以通过 PING
,PONG
的消息传播完成集群状态在每个实例的传播同步。
Gossip 消息
发送的消息结构是 clusterMsgDataGossip
结构体组成:
```c++
typedef struct {
char nodename[CLUSTER_NAMELEN]; //40字节
uint32_t ping_sent; //4字节
uint32_t pong_received; //4字节
char ip[NET_IP_STR_LEN]; //46字节
uint16_t port; //2字节
uint16_t cport; //2字节
uint16_t flags; //2字节
uint32_t notused1; //4字节
} clusterMsgDataGossip;
所以每个实例发送一个 `Gossip`消息,就需要发送 104 字节。如果集群是 1000 个实例,那么每个实例发送一个 `PING` 消息则会占用 大约 10KB。
除此之外,实例间在传播 Slot 映射表的时候,每个消息还包含了 一个长度为 16384 bit 的 `Bitmap`。
每一位对应一个 Slot,如果值 = 1 则表示这个 Slot 属于当前实例,这个 Bitmap 占用 2KB,所以一个 `PING` 消息大约 12KB。
`PONG`与`PING` 消息一样,一发一回两个消息加起来就是 24 KB。集群规模的增加,心跳消息越来越多就会占据集群的网络通信带宽,降低了集群吞吐量。
## 实例的通信频率
> 65 哥:码哥,发送 PING 消息的频率也会影响集群带宽吧?
Redis Cluster 的实例启动后,默认会每秒从本地的实例列表中随机选出 5 个实例,再从这 5 个实例中找出一个最久没有收到 PING 消息的实例,把 PING 消息发送给该实例。
> 65 哥:随机选择 5 个,但是无法保证选中的是整个集群最久没有收到 PING 通信的实例,有的实例可能一直没有收到消息,导致他们维护的集群信息早就过期了,咋办呢?
这个问题问的好,Redis Cluster 的实例每 100 ms 就会扫描本地实例列表,当发现有实例最近一次收到 `PONG` 消息的时间 > `cluster-node-timeout / 2`。那么就立刻给这个实例发送 `PING` 消息,更新这个节点的集群状态信息。
当集群规模变大,就会进一步导致实例间网络通信延迟怎加。可能会引起更多的 PING 消息频繁发送。
### 降低实例间的通信开销
- 每个实例每秒发送一条 `PING`消息,降低这个频率可能会导致集群每个实例的状态信息无法及时传播。
- 每 100 ms 检测实例 `PONG`消息接收是否超过 `cluster-node-timeout / 2`,这个是 Redis 实例默认的周期性检测任务频率,我们不会轻易修改。
所以,只能修改 `cluster-node-timeout`的值:集群中判断实例是否故障的心跳时间,默认 15 S。
所以,**为了避免过多的心跳消息占用集群宽带,将 `cluster-node-timeout`调成 20 秒或者 30 秒,这样 `PONG` 消息接收超时的情况就会缓解。**
但是,也不能设置的太大。都则就会导致实例发生故障了,却要等待 `cluster-node-timeout`时长才能检测出这个故障,影响集群正常服务、
# 总结
「码哥字节」不跟风不扯淡,助力程序员成长。
《Redis 系列》至今已发布 7 篇,每一篇「码哥字节」都耗费大量精力,精益求精。确保每一篇都给读者带来价值,让大家得到真正的提升。
- [哨兵集群实现故障自动转移](https://mp.weixin.qq.com/s/rtgh5c6p5zhcfgGeqX5mZA),但是当数据量过大导致生成 RDB 时间过长。而 Fork 执行的时候会阻塞主线程,由于数据量过大导致阻塞主线程过长,所以出现了 Redis 响应慢的表象。
- 使用 Redis Cluster 集群,主要解决了大数据量存储导致的各种慢问题,同时也便于横向拓展。**在面向百万、千万级别的用户规模时,横向扩展的 Redis 切片集群会是一个非常好的选择。**
- 集群的整个数据库被分为 16384 个槽(slot),数据库中的每个键都属于这 16384 个槽的其中一个,集群中的每个节点可以处理 0 个或最多 16384 个槽。
- Redis 集群节点采用 Gossip 协议来广播自己的状态以及自己对整个集群认知的改变。
- 客户端连接到集群候任何一个实例后,实例会将哈希槽与实例映射信息发送给客户端,客户端将信息保存,用于将 key 定位到对应的节点。
- 集群并不能无限增加,由于集群通过 `Gossip`协议传播集群实例信息,所以通信频率是限制集群大小的主要原因,主要可以通过修改 `cluster-node-timeout`调整频率。
原创不易,如果觉得文章不错,希望读者朋友点赞、收藏和分享。
以上是关于MySQL到底能支持多大的数据量的主要内容,如果未能解决你的问题,请参考以下文章