签到23!
学习总结
三军可夺气,将军可夺心。是故朝气锐,昼气惰,暮气归。
善用兵者,避其锐气,击其惰归,此治气者也。
以治待乱,以静待哗,此治心者也。
以近待远,以佚待劳,以饱待饥,此治力者也。
无邀正正之旗,勿击堂堂之阵,此治变者也。
1、为什么要分库分表
数据库出现瓶颈
-
无法获取连接
高并发情况下连接数不够
-
操作数据变慢
数据库处理数据出了问题
-
存储出现问题
单机保存的数据量太大
总结:受到了硬件的限制:CPU、内存、网络、磁盘等;
数据库优化方案
-
SQL和索引
优化SQL,最终目标其实使用索引,最容易最常见的方案
-
表和存储引擎
数据放在表,表存在存储引擎上,不同的存储引擎特性有利于特定业务的处理;
对表的进行分区、表结构进行优化、表字段进行冗余或者表字段定义的优化等;
-
架构
如果是一个数据库服务器,建立多个实例,进行集群,负载均衡
主从服务器,从服务器为读数据库,主服务器用于写
数据库之上加一层缓存,如redis
为了减轻数据库的存储压力和访问压力,分库分表
-
配置
优化数据库的配置,如缓存区大小、连接数等,其实更高效的利用硬件
-
操作系统和硬件
总结:优化从上到下,成本越高
什么时候进行分库分表
- 一个表存储多少条数据之后
- 一天能产生多少数据以后
- 访问数据的话,查询时间超过多少秒以后
2、架构演进
-
单体架构
所有代码打包成一个war包,部署到一个tomcat中,运行在一个进程中;
当业务渐渐增加后,业务代码也越来越多,系统越来越臃肿。
为了优化系统,搭载集群,负载均衡,加缓存、优化数据库、优化业务代码;
问题依然存在;
-
多应用单数据库
对代码进行解耦,对职责进行拆分,出现问题可以快速定位和修改;
业务系统拆分为,客户系统、订单系统、财务系统等;
但访问同一个数据库,数据库的压力依然存在;
-
多应用多数据库
每一个应用系统对应一个数据库;
分库解决了具体实际问题
-
分表
分库之后,有些库的表依然会增长很快,进行分表,单表分多个;
总结:架构的演进不是一开始就确定了的,而是一步一步进行,不要过度架构,增加复杂度;
3、如何分库分表
分库分表的维度:
-
垂直拆分
基于表结构的拆分,表结构不同;有单库的分表、多库的分库;并没有解决单表数据量大的问题
-
单库垂直分表
如将商品信息表,分基本信息表、联系方式表、结算信息表等
-
多库的垂直分表
将以前一个库中的表根据业务拆分到不同的数据库中,如将与客户相关的表,拆分到客户数据库中;
-
-
水平拆分
基于数据的拆分,表结构相同;有同库的水平切分也有多库的水平拆分;为了解决单表数据量大需要水平拆分
-
单库水平分表
把一个表按照创建时间,分当月表、当天表、历史数据表等;
如每一天建一个当天表
解决了单表的查询问题,单并不能解决存储问题,单库数据依然很多
-
多库水平分表
能解决实际问题,也带来新的问题
-
4、分库分表的问题
跨库关联查询
解决方案:
-
字段冗余
-
数据同步
如商品库要查产品库,干脆在商品库中创建产品表,做一个定时任务去同步数据
-
全局表
每个库中都有该表,数据一致
-
ER表(关联表)
相互关联的表及数据一定在同一个库中
-
重新组装
每个库每个表查询出来,重新过滤组装,实在没办法的办法
分布式事务
CAP原则:一致性、可用性、分区隔离性;
BASE原则:基本可用、软状态、最终一致性;
解决方案:
-
全局事务
询问每一个事务是否可以提交,两阶段提交
-
基于可靠消息服务的事务方案
使用消息中间件提供可靠消息服务
-
TCC柔性事务
请求多系统预留资源处理,两阶段提交
-
最大努力通知
通过消息中间件,重复提交、定期校对
排序、翻页、函数计算问题等
全局主键避重问题
解决方案:
-
UUID
-
数据库
在数据库中定义一个表来存储字段规则,如起始位置、位数、类型及当前值等。先用for update 行锁,性能问题大;
-
redis
incr原子递增特性
-
雪花算法
41位的时间戳+10位机器id+12毫秒内的流水号+0
依赖于机器时间
5、多数据源的读写解决方案
在javaweb中一般的sql运行流程:
Dao—->Mapper(ORM)—>Jdbc—>代理—–>数据库服务
-
DAO层
在选择数据源之前,根据一定的规则选择数据源进行操作;
Spring中提供了AbstractRoutingDataSource