发布时间:2023-11-12
浏览次数:0
大家好,我是顶级建筑师。
一、概述
顺应趋势,大数据的高并发需要不断的系统升级,分库分表就是其中之一。
2、为什么要分库分表?
场景:随着互联网技术的蓬勃发展,大数据、高并发是很多企业遇到的情况。 例如,随着公司业务的发展,系统用户数量迅速增加。 系统每天会新增10万条数据,一个月会新增300万条数据。 单表数据量已达到数百万,高峰期请求数达到1000次。 处理的办法是我们在线部署几台机器,使用nginx做负载均衡,数据库支持足够。 然而,数据量不断增长,下一步我们该怎么办?
当每天有几千万的活跃用户,单表每天新增数据多达50万条时,一张表的总数据量就达到了20~3000万。 数据库磁盘容量不断被消耗,并发峰值达到惊人的5000。 ~! 此时,单一数据库已经无法抵抗。
3、分表3.1、分表计划
当单表达到千万级时,单表数据量过大,会极大影响SQL执行的性能。 稍后,你的 SQL 可能会运行得很慢。 一般来说,当单表达到几百万的时候,性能会比较差,就会出现分表的情况。
对数值取模
使用Id取模的方法来划分表格。 例如表示例中,表根据cusno字段分为4个库。 余数为0的放入第一库,余数为1的放入第二库,余数为2的放入第三库。 ,余数为3的放入第三库。 这样,同一个用户的数据就会分散到不同的表中。 如果查询条件包含cusno字段,则可以明确定位对应的表进行查询。
示例描述:
// 首先创建三个表,然后我创建一个uuid表,用于提供自增id。
create table **customer0**(
id int unsigned primary key ,
name varchar(32) not null default '',
pwd varchar(32) not null default ''
)engine=myisam charset utf8;
create table **customer1**(
id int unsigned primary key ,
name varchar(32) not null default '',
pwd varchar(32) not null default ''
)engine=myisam charset utf8;
create table **customer2**(
id int unsigned primary key ,
name varchar(32) not null default '',
pwd varchar(32) not null default ''
)engine=myisam charset utf8;
create table **customer3**(
id int unsigned primary key ,
name varchar(32) not null default '',
pwd varchar(32) not null default ''
)engine=myisam charset utf8;
create table **uuid**(
id int unsigned primary key auto_increment
)engine=myisam charset utf8;
**利用以上创建的表进行业务处理**
@Service
public class CustomerService {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 注册的代码
* @param name
* @param pwd
* @return
*/
public String regiter(String name,String pwd){
//1.生成cusno ,- 先获取到 自定增长ID
String insertUUidSql = "insert into uuid values(null)";//插入空数据,这里的id是自动增长的
jdbcTemplate.update(insertUUidSql);//执行
//查询到最近的添加的主键id
Long cusno = jdbcTemplate.queryForObject("select last_insert_id()", Long.class);
//2.存放具体的那张表中 - 也就是判断存储表名称
String tableName = "customer" + cusno % 3;
//3.插入到具体的表中去- 注册数据
String insertUserSql = "INSERT INTO " + tableName + " VALUES ('" + cusno + "','" + name + "','" + pwd + "');";
System.out.println("insertUserSql:" + insertUserSql);
jdbcTemplate.update(insertUserSql);
return "success";
}
/**
* 通过cusno查询name
* @param userid
* @return
*/
public String get(Long cusno) {
//具体哪张表
String tableName = "customer" + cusno % 3;
String sql = "select name from " + tableName + " where id="+cusno;
System.out.println("SQL:" + sql);
return jdbcTemplate.queryForObject(sql, String.class);//执行查询出name
}
}
优缺点总结
优势:
将一张数据表的数据划分为多张表后,数据会比较均匀,这样会减少高并发访问对数据库造成的压力。
缺点:
如果后期扩容,则需要迁移旧数据并重新计算。
跨表查询的复杂度增加。 例如上例中,如果经常使用的查询条件中不包含cusno,则不会定位到数据库。 因此,需要同时向四个库发起查询,然后合并内存中的数据,取最小集合返回给应用程序。 相反,图书馆成了一个累赘。
根据数值范围
为了解决后期集群扩容时迁移旧数据的问题,可以使用按日期或ID进行表分区。 例如:将不同月份甚至几天的数据按日期分布到不同的表中; 将 从 1 到 9999 的记录分配给第一个表,将 10000 到 20000 的记录分配给第二个表,依此类推。 从某种意义上说,一些系统中采用的“冷热数据分离”,将一些较少使用的历史数据迁移到其他库,只在业务功能中提供热数据查询,也是类似的做法。
的优点和缺点
优势:
单台尺寸可控
横向扩展自然很容易。 如果后续想要扩展整个分片集群,只需要添加节点即可,不需要迁移其他分片的数据。
使用分片字段进行范围搜索时,连续分片可以快速定位分片进行快速查询,有效避免跨分片查询问题。
缺点:
热数据成为性能瓶颈。 连续分片可能存在数据热点,例如按时间字段分片。 有些分片存储的是最近一段时间的数据,可能被频繁读写,而有些分片存储的是很少被查询的历史数据。
4. 分库
即一个数据库一般最多可以支持2000个并发。 随着查询量的增加,单个数据库服务器已经无法支持。 此外,为了获得健康的单数据库并发值,最好保持在每秒 1000 个左右。 不要太大,否则会引起问题。 导致单个DB的存储空间不足。 然后就可以将一个库的数据拆分成多个库,访问时访问一个库。
垂直分割
垂直拆分就是对数据库的列进行处理,列与对应的业务相关。 这意味着相关性较低的不同表根据业务耦合存储在不同的数据库中。 另外,搜索公众号Linux,了解如何在后台回复“git books”,即可获得惊喜大礼包。
考虑到微服务,该方法类似于将一个大系统拆分为多个小系统。 它们按照业务分类独立划分,每个微服务使用独立的数据库。 例如,最初有一个包含用户表的数据库。 随着公司业务的发展,技术团队成员也随之扩大,分为不同的技术组,不同的组负责不同的业务模块。比如A团队负责用户模块,B团队负责产品模块,分为库和库。
需要解决的问题:跨库事务、jion查询等。
水平分割
按照规则,一般是水平分库在垂直分库之后。 例如,每天处理的订单量是海量的,可以按照一定的规则和级别进行划分。 例如,表太大,无法存储在单个数据库中,或者访问性能受到压力。 将一个表拆分为多个表,每个表存储部分记录并保存在不同的数据库中。 水平拆分需要对系统进行重大改变。 。
1)纵向扩展,升级数据库所在物理机,提高内存/存储/IO性能。 但这种升级成本高昂,且只能满足短期需求。
2)横向扩展,将订单库拆分为多个库,分发到多台机器上存储和访问。 这种方式支持横向扩展,可以满足长期需求。
订单数据库主要包括订单主表/订单明细表(记录产品详细信息)/订单扩展表。 水平分库将这三个表的记录划分到多个数据库中。 订单横向分库效果如下图:
数据库分片策略:类似于水平分表
分库维度确定后,如何将记录划分到各个数据库中? 一般有两种方式:
根据取值范围,例如将用户ID为1-9999的记录分配给第一库,将用户ID为10000-20000的记录分配给第二库,以此类推。
根据取模值intellij idea 数据库关系图,例如用户ID mod n,余数为0的记录放入第一个库,余数为1的记录放入第二个库,以此类推。
需要解决的问题:数据路由、组装。
读写分离
对于时间不敏感的数据,可以通过读写分离的方式缓解数据库压力。
需要解决的问题:区分允许一定时间延迟的业务、数据同步问题。
垂直分库-->水平分库-->读写分离
五、分裂后面临的新问题的解决办法
常用解决方案:站在巨人的肩膀上可以省很多力气。 目前,已经有一些相对成熟的分库分表开源解决方案。 扩展:
使用第三方数据库中间件(Atlas、Mycat、TDDL、DRDS),业务系统需要配合数据存储的升级。 综合考虑后,其实建议考虑-jdbc和Mycatintellij idea 数据库关系图,这两个都可以考虑使用。
-jdbc 这一层方案的优点是不需要部署,运维成本低,不需要代理层二次转发请求,性能较高。 不过如果有升级什么的,每个系统都需要重新升级版本才发布。 每个系统都需要-jdbc依赖;
Mycat的代理层方案的缺点是需要自己部署和运维一套中间件,运维成本较高。 但好处是对每个项目都是透明的。 如果遇到升级之类的,通过自己的中间件来处理即可。 。
一般来说,两种方案都可以使用,但我个人建议中小型公司选择-jdbc。 该层解决方案重量轻,维护成本低。 不需要额外的人力,中小型公司的系统复杂度会更低。 ,项目不多; 不过中大型公司最好选择Mycat之类的代理层解决方案,因为大公司可能系统和项目很多,团队很大,人员充足,所以最好有专门的人来研究和维护他们。 mycat,然后大量的项目就可以直接透明的使用了。
随附的:
负载均衡:车辆超载,多车运输物料。 有一个总调度中心分配每辆车的重量和拉动的货物量。 系统中,总调度中心可以是nginx。 通过配置多台服务器的IP地址,进行权重分配,并采用轮询算法实现处理大并发的策略。
主键生成策略:
欢迎大家互相讨论、碰撞、发表意见。 如果有什么问题也可以和我交流。
最后,我们整理了一份BAT各大公司的真实面试题清单,供读者参考。 如果您需要,可以扫描二维码并回复“面试问题”即可获取。
公众号后台回复结构或结构整齐有惊喜大礼包!
顶尖建筑师交流群
《顶尖建筑师》专门为读者和建筑师建立了交流群。 可以添加小编微信进群。 欢迎有想法、愿意分享的朋友一起交流学习。
扫一扫添加好友邀请您加入建筑师群。 添加我时请注明【姓名+公司+职位】
如有侵权请联系删除!
Copyright © 2023 江苏优软数字科技有限公司 All Rights Reserved.正版sublime text、Codejock、IntelliJ IDEA、sketch、Mestrenova、DNAstar服务提供商
13262879759
微信二维码