数据层的扩展问题
随着业务的增长,数据层面临的压力会越来越大,单机数据库已经不足以支撑。对于大多数的业务场景来说,数据的操作都是读多写少,而且读都集中在少部分的热点数据上。
我们首先想到的是引入缓存层来缓解数据库的读压力;如果缓存容量需求比较大,可以构建缓存集群,在上层按照Consistent Hashing算法将数据分散到多个节点,后续需要增加新缓存节点时,只有少部分的数据会失效。
接着引入新的数据库种类。Redis已经成为诸多企业的首选标配,因为其支持丰富的数据类型和数据查询接口,且内存型的数据库天然具有更高的性能。
你可以将业务中关系性要求不高的数据,从MySQL转移到Redis中,尤其是列表类的数据以及计数统计类的数据。给MySQL减负的同时提高数据的查询性能。如果单台Redis节点不能满足你对容量的需求, QingCloud平台提供了支持多主多从Redis 3.0集群服务,一方面可对数据自动分区提高存储容量,另一方面保证了服务的高可用性。
对于MySQL的扩展可以分为几个步骤来做。
首先,增加MySQL slave节点,在上层将部分读请求分发到slave节点上去。由于slave同步可能有延时,业务应该能容忍短暂的数据不一致现象。例如你的一个用户修改了年龄属性,其他用户要等一会儿才能看到他的新年龄。QingCloud MySQL数据库支持一主多从的架构,并且已经在多个从节点之上做好了负载均衡,你可以轻易在界面上操作增加新的从节点来为你分担读压力。
即便有slave作为数据副本,你也应该定期对你的数据库进行冷备份,方便当业务出现误操作时,能够回滚或恢复到曾经的某个时间点。在QingCloud平台上,备份的过程可以手动执行或者配置为自动任务,在备份过程中对数据库正常使用没有影响。
其次,随着数据的增长,单个数据库不能承载完整的数据集合,并且写操作对于单库的压力越来越明显,你应该考虑分库、分表技术。将比较庞大的数据表拆分出来单独存放,可以给主数据库腾出来一部分空间,分担读写压力。拆分的时候,还可以按照功能逻辑,把相关联的数据表存在一个库里。
第三,当数据库单表非常庞大,对读写都造成瓶颈时,你需要开始考虑水平分表sharding。这种扩展方式可以同时解决单表容量过大,读压力和写压力很大的问题,但带来的研发和运维难度也会增大,推荐把上述的优化做完以后,最后在有必要的情况下再做这一步。
这里简略说一下水平分表的要点。首先要从数据表的字段中,选择一个合理的分区键(shard key),这个键应该是所有该表查询条件里,最经常用到的字段,这样才会使大部分的查询,能够提前判断应该向哪些特定的分区发送请求,如果查询条件中不带分区键,需要遍历所有的分区,并将结果进行merge。
有了shard key还要设计一种分区算法。比如常见的有按照区间,如user_id in [0, 100] 在shard 1, user_id in [101, 200] 在shard2,还比如按照Hash取模等等。设计分区算法的时候要充分考虑业务特点,多从读写操作的角度思考,这样设计能否将I/O压力和数据均匀分摊到每个shard上去。
最后,还需要考虑数据层的扩展如何对上层透明。比如引入分布式数据库中间件,或者结合业务逻辑把数据库操作做成一个独立的子服务,供其它服务调用。如果不做成子服务,至少在业务代码里有独立的一层来封装对数据库的操作。
至此,数据层的扩展示意图如图4所示。
图4
除了上述的结构化数据的存取以外,企业还有存储海量小文件数据(非结构化数据)的需求。单机硬盘、LVM和NAS可以作为临时方案使用,但都无法同时满足无限容量、高性能、高安全性、高可用性的多重需要。而自行搭建分布式存储系统,如Ceph、GlusterFS、HDFS适用场景非常有限,且运维和二次开发的成本也非常高。
在QingCloud平台上用户可以使用QingStor对象存储服务来存储海量的数据文件,服务本身提供了无限容量、高扩展性、高可用性和高安全性的特性。