你好,欢迎进入江苏优软数字科技有限公司官网!

诚信、勤奋、创新、卓越

友好定价、专业客服支持、正版软件一站式服务提供

13262879759

工作日:9:00-22:00

千万级并发架构下,关系型数据库应该如何优化?

发布时间: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)横向扩展,将订单库拆分为多个库,分发到多台机器上存储和访问。 这种方式支持横向扩展,可以满足长期需求。

订单数据库主要包括订单主表/订单明细表(记录产品详细信息)/订单扩展表。 水平分库将这三个表的记录划分到多个数据库中。 订单横向分库效果如下图:

intellij idea 数据库关系图_关系库的标准语言_数据库中关系图怎么出来

数据库分片策略:类似于水平分表

分库维度确定后,如何将记录划分到各个数据库中? 一般有两种方式:

根据取值范围,例如将用户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地址,进行权重分配,并采用轮询算法实现处理大并发的策略。

主键生成策略:

intellij idea 数据库关系图_数据库中关系图怎么出来_关系库的标准语言

欢迎大家互相讨论、碰撞、发表意见。 如果有什么问题也可以和我交流。

最后,我们整理了一份BAT各大公司的真实面试题清单,供读者参考。 如果您需要,可以扫描二维码并回复“面试问题”即可获取。

公众号后台回复结构或结构整齐有惊喜大礼包!

顶尖建筑师交流群

《顶尖建筑师》专门为读者和建筑师建立了交流群。 可以添加小编微信进群。 欢迎有想法、愿意分享的朋友一起交流学习。

扫一扫添加好友邀请您加入建筑师群。 添加我时请注明【姓名+公司+职位】

如有侵权请联系删除!

13262879759

微信二维码