完整内容地址:https://my.oschina.net/bianxin/blog/3035494
前言
作为一个全球人数最多的国家,一个再怎么凄惨的行业,都能找出很多的人为之付出。而在这个互联网的时代,IT公司绝对比牛毛还多很多。但是大多数都是创业公司,长期存活的真的不多。大多数的IT项目在注册量从0-100万,日活跃1-5万,说实话就这种系统随便找一个有几年工作经验的高级工程师,然后带几个年轻工程师,随便干干都可以做出来。
因为这样的系统,实际上主要就是在前期快速的进行业务功能的开发,搞一个单块系统部署在一台服务器上,然后连接一个数据库就可以了。接着大家就是不停的在一个工程里填充进去各种业务代码,尽快把公司的业务支撑起来。
但是如果真的发展的还可以,可能就会遇到如下问题:
在运行的过程中系统访问数据库的性能越来越差,单表数据量越来越大,一些复杂查询 SQL直接拖垮!
这种时候就不得不考虑的解决方案:缓存,负载均衡,项目分块(微服务);数据库:读写分离,分库分表等技术
如果说此时你还是一台数据库服务器在支撑每秒上万的请求,负责任的告诉你,每次高峰期会出现下述问题:
- 数据库服务器的磁盘 IO、网络带宽、CPU 负载、内存消耗,都会达到非常高的情况,数据库所在服务器的整体负载会非常重,甚至都快不堪重负了。
- 高峰期时,本来你单表数据量就很大,SQL 性能就不太好,这时加上你的数据库服务器负载太高导致性能下降,就会发现你的 SQL 性能更差了。
- 最明显的一个感觉,就是你的系统在高峰期各个功能都运行的很慢,用户体验很差,点一个按钮可能要几十秒才出来结果。
- 如果你运气不太好,数据库服务器的配置不是特别的高的话,弄不好你还会经历数据库宕机的情况,因为负载太高对数据库压力太大了。
其实大多数公司的瓶颈都在数据库,其实如果把上面的解决方案,都实现了,基本上就没的什么问题了,举例:
如果订单一年有 1 亿条数据,可以把订单表一共拆分为 1024 张表,分散在5个库中,这样 1 亿数据量的话,分散到每个表里也就才 10 万量级的数据量,然后这上千张表分散在 5 台数据库里就可以了。
在写入数据的时候,需要做两次路由,先对订单 id hash 后对数据库的数量取模,可以路由到一台数据库上,然后再对那台数据库上的表数量取模,就可以路由到数据库上的一个表里了。
通过这个步骤,就可以让每个表里的数据量非常小,每年 1 亿数据增长,但是到每个表里才 10 万条数据增长,这个系统运行 10 年,每个表里可能才百万级的数据量。
全局唯一ID
在分库分表之后你必然要面对的一个问题,就是 id 咋生成?因为要是一个表分成多个表之后,每个表的 id 都是从 1 开始累加自增长,那肯定不对啊。
举个例子,你的订单表拆分为了 1024 张订单表,每个表的 id 都从 1 开始累加,这个肯定有问题了!
你的系统就没办法根据表主键来查询订单了,比如 id = 50 这个订单,在每个表里都有!
所以此时就需要分布式架构下的全局唯一 id 生成的方案了,在分库分表之后,对于插入数据库中的核心 id,不能直接简单使用表自增 id,要全局生成唯一 id,然后插入各个表中,保证每个表内的某个 id,全局唯一。
比如说订单表虽然拆分为了 1024 张表,但是 id = 50 这个订单,只会存在于一个表里。
那么如何实现全局唯一 id 呢?有以下几种方案:
方案一:独立数据库自增 id
这个方案就是说你的系统每次要生成一个 id,都是往一个独立库的一个独立表里插入一条没什么业务含义的数据,然后获取一个数据库自增的一个 id。拿到这个 id 之后再往对应的分库分表里去写入。
比如说你有一个 auto_id 库,里面就一个表,叫做 auto_id 表,有一个 id 是自增长的。
那么你每次要获取一个全局唯一 id,直接往这个表里插入一条记录,获取一个全局唯一 id 即可,然后这个全局唯一 id 就可以插入订单的分库分表中。
这个方案的好处就是方便简单,谁都会用。缺点就是单库生