MySQL本身不是分布式系统,其支持的数据复制技术,本质上是为了数据容灾使用,但目前基于主从复制进行读写分离,减少单机的读压力。 |
目标
数据存储资源是系统中最重要的组成部分,数据即一切,尤其分布式领域,主要关注以下几点:
- 高可用性,当遇到网络或者系统故障时,系统仍然保持可用
- 高扩展,当数据规模变大时,数据存储系统能够自动适应这种变化
- 高性能,当数据规模和访问规模变大时,性能不受大的影响
- 成本,通过成本反映出系统设计是合理的
- 安全,遇到各种系统和人为故障时,数据不丢失
MySQL
MySQL是OLTP关系型数据库,支持ACID事务,是最主要的存储系统,目前使用的版本是5.7。MySQL本身不是分布式系统,其支持的数据复制技术,本质上是为了数据容灾使用,但目前基于主从复制进行读写分离,减少单机的读压力。
MySQL服务如果托管在阿里云,可以使用高可用版本,秒级的主从切换,基于云盘的磁盘扩容技术,能够快速复制一个只读节点,减少了很多自建MySQL遇到的各种问题,另外其还提供了很多额外的功能,比如索引分析、SQL审查、慢查询分析、动态扩容。
虽然云托管RDS,但本质上还是MySQL,仍然会遇到很多问题,比如:
- 数据存储不支持分片,只能通过分库分表的方式进行横向扩展,目前应用层也不支持分库分表的路由,即使分表,拆分表的时候还是会遇到很多问题
- 如果表设计和索引设计不合理,大量的更新,仍然会遇到主从延迟的问题,从应用层面是很难彻底解决的
- 阿里云RDS只支持一个负载均衡主从分离,所以后台、队列应用使用360 Atlas读写分离服务,目前是一个单点,且也会影响读写性能。
- MySQL应用规范目前还没有建立,比如什么样的应用应该选择MySQL,使用MySQL很大程度是为了事务,如果没有事务的场景是否可以选择其他的数据库?
- 阿里云官方提到,单表记录数超过500w,性能会极具下降
- DDL操作,尤其对于大表操作,会引起很大的同步延迟问题
云托管的RDS本质上还是基于ECS+云盘搭建的,数据的增长、备份、性能、迁移、升级、只读实例、磁盘容量、Binlog延迟还是会显露出来。
那未来如何?其实云厂商也在探索,提出了云原生数据库、云原生分布式数据的概念,比如阿里云的PolarDB、PolarDB-X。云原生数据库关注成本、性能、在线业务扩展、数据安全,它的核心技术包括计算和存储分离,物理复制Binlog行复制模式,共享存储设备,存储之间通过RDMA高速网络协议传输,同时PolarDB-X支持分区模式,解决了分库分表的问题。
经过这些创新,传统MySQL的弊端被解决了,比如同步延迟、备份、成本、分库分表、性能。未来,可以将核心数据库迁移至云原生数据库,保障核心业务的稳定性和扩展性,而对于非OLTP业务可以选择其他数据库,且制定MySQL应用规范,明确哪些业务模式使用MySQL,索引正确设计、容量规划、SQL语句使用规范等等。
Redis
Redis是K/V数据库,它基于单线程、内存操作,所以性能非常高。另外支持丰富的数据结构,比如字符串、Hash、List、集合,应用场景非常广泛。它通过AOF和RDB保障数据持久化,通过复制技术进行数据备份,也支持通过哨兵和分区提供高可用性和容量伸缩,通过LUA脚本支持多条命令的事务操作。
Redis虽然是一个单机系统,但通过复制、集群技术也可以认为是一个分布式存储系统,目前西五街在大量使用,主要分为三类应用:
- 存储,比如用户积分、文章数等数据,这些数据不能丢
- 缓存,比如用户文章列表数据,需要考虑缓存穿透和雪崩等问题
- 消息队列,目前逐步替换为Kafka等纯消息系统
阿里云云托管Redis社区版5.0服务集群版。
在应用设计上存在以下几个问题:
- 存储和缓存混合使用,无法拆分,对于容量估算不透明
- 应用模式上,没有很好的规范,比如缓存更新机制标准、统一Lib应用包
通过阿里云Redis提供的部署架构,可以很好的理解它的应用场景:
- 标准版-双副本:服务可靠,数据可靠,比较标准的使用模式,不管是存储还是缓存服务都可用
- 集群版:通过代理模式和分片可以构建出一个可伸缩的集群模式,解决Redis自身单线程瓶颈,满足大容量、高性能的业务需求,而且副本集主要做恢复用,很适合存储场景,不存在同步延迟的问题
- 读写分离架构:对于不关注同步延时的问题,比如缓存场景,可以选择这种模式,当容量不够的适合,通过客户端的一致性Hash技术扩容多个Redis实例就可以
后续确定Redis使用规范,拆分存储和缓存场景,基于统一Lib包,就能解决大部分问题。
Elasticseach
Elasticseach是一个近实时的分布式搜索引擎和分析引擎。作为一个搜索引擎,目前在开源领域已经是排名第一的数据库了;基于倒排索引,具有很强的检索能力,所以不管是应用还是在大数据领域,它都是一个非常通用的分析引擎。
近实时表示Elasticseach应用场景必须要有所了解,它不支持ACID,所以无法是一个OLTP数据库,但使用压力小了很多,在做策略分析、后台应用、即时查询上有很广泛的场景。作为一个分布式应用,通过副本集机制解决高可用的问题,能够解决单机故障的问题,但如果数据被误删除,还是需要有备份机制,比如Elasticseach的快照机制。
副本集的同步最终达到一致性,为了写入性能,也可以配置主节点写入完成即返回给客户端。在容量可扩展方面,可以采用分片机制解决容量横向伸缩的问题,将数据分到不同节点的不同分片上,如果要调整分片,需要reindex。
在性能方面,通过多副本集节点分担查询压力。也可以使用专门的Transport节点分担date Node节点的压力,将分片查询,副本查询等路由和合并动作的结果汇总起来。Elasticseach是ELK解决方案的一部分,其还包括很多服务,包括Filebat,Kibana,Logstash,在大数据领域也是很好的一个方向。Elasticseach是在ELK上搭建的三节点服务,由于规模问题,目前也很少使用分片技术。核心是文章大宽表,用户大宽表。结合了搜索场景和分析场景,通过Binlog+Canal+Kafka+Go服务将MySQL多个表汇总到一个大宽表,主要是文章信息的大宽表,一方面是满足搜索场景,另外满足策略和应用场景。
现在大宽表的应用模式非常多,基于Free Schema模式,查询模式非常灵活,通过订阅方式同步数据,也减轻了应用层的负担,数据正确性有很大的保障。未来,对于Elasticseach的应用,一方面要加强性能调优,比如分片数据的不均匀,查询性能的优化,同时要提升可维护性,比如挖掘reindex、alias等功能,充分理解Elasticseach。而在国内的云厂商中,都没有对Elasticseach做太大的升级,基本上就是将Elasticseach服务托管到云中。
Kakfa
Kakfa是一个分布式的高吞吐消息队列,订阅/消费模式追求的是高性能,而非存储容量。但其日志本身具有重放功能,也可以理解为一个分布式存储系统。
Kafka的核心功能包括:解耦、消峰、缓存,应用场景极为广泛,是系统不可缺少的一个组件。作为分布式系统,它也有副本和分区机制,从而保障高可用和高吞吐。通过segment顺序写,保障了写性能非常高,而基于消费组组的概念,消费者吞吐能力也能横向扩展。同时每个broker都能负责查询,提升了吞吐能力。Kafka基于Zookeeper做很多分布式管理功能,包括Leader选举,负载均衡,Meta存储。目前Kafka三节点集群是通过ECS自行搭建的,运行近一年,服务相对稳定,可维护性也较好,没有太多的管理工作,很多核心服务都已经使用了Kafka队列,后续原有基于Redis的队列也可以尽快迁移。
MongoDB
MongoDB是一个分布式的文档数据库,其目标是一个支持ACID事务的分布式数据库,因为是面向文档,所以模式非常灵活,结构松散,使用场景很规范,相比MySQL,其二进制的存储模式,压缩比非常高,存储成本会大幅减少,同时基于WiredTiger引擎,能够创建各种类型的索引,甚至子文档也能创建索引,从而提升查询性能
MongoDB通过oplog技术支持副本集,也支持分区,分区键可以自定义,因为有了分区,所以额外有了mongos路由服务器,config服务器,mongos路由服务器通过查询config服务器,向节点和分区发送服务。MongoDB将一致性和性能诉求交给了客户端,通过read concern、write concern、read perference技术提供多种灵活性,比如你要求强一致性,那么就采用majority,你要求数据永远不丢失就配置journal为真。MongoDB 4.0和MongoDB 4.2支持多文档的事务,分别支持复制集、分区维度的事务性,但使用和理解非常复杂,可能是分布式系统中最难学习的部分。
这样说明,不用刻意使用事务,对MongoDB进行良好的建模,做OLTP关系数据的补充,其在性能、成本、高可用、伸缩性方面是有优势的。其实在MySQL中,目前我们也很少使用跨表,跨语句的事务,所以不要太迷信事务,选择好应用场景。除了查询,MongoDB也支持各种聚合操作,在分析领域也很有广泛的使用场景,这一点和Elasticseach很类似。
目前MongoDB三节点集群是通过ECS自行搭建的,存储规模较小,使用场景较少。对比MySQL和Elasticseach,MongoDB还是有很广泛的应用场景,比如分析场景,对事务要求不高的场景,数据增长比较大的场景(比如私信数据),业务模式比较灵活的场景(比如各种条件的查询,聚合操作)。不过和Elasticseach一样,各大云厂商一样,只是将这个服务托管到云,并没有做太多的优化。