如何构建高性能读写服务

高性能读取服务

现实中一般只有两种业务,一种是读取比较多的场景,一种是写入比较多的常见,一般面向最终消费者的业务读取会比写入多,比如:新闻类网站,购物类等,写入比较多的有ERP系统,银行业务等,这些一般都是面向企业客户级别的。不同的场景处理的方式也不一样,对于读取比较多的场景,最常见的手段就是使用缓存解决,俗话说,性能不够,缓存来凑,而对于写入比较多的场景,一般采用队列解决,通过最终一致性来解决问题,当然有些对实时时要求比较高的场景,毕竟是少数,这些业务一般是一些大型企业,处理方式一般是拼硬件的方式,因为大企业一般不差钱。

缓存这块最大的问题是缓存一般采用非关系数据库而实际的业务是写入到关系数据库,写入时一般采用双写的机制进行,但是因为时异构数据库所以事务很难保证,所以会出现要么缓存写入失败要么数据库写入失败的场景,缓存的写入也有两个选择,一个是更新缓存,一个是删除缓存。

以上问题都比较简单,也是面试过程中常见的问题,稍微有点经验的人都不会有太大的问题,先说说常规的做法,对于双写问题一般是先写数据库,再删除缓存,但是这种做法只能减少出错的可能性,不能完全避免数据库和缓存不一致,因为删除缓存的过程可能会失败,这样导致用户看到的数据不是最新的,只能等缓存过期后才能得到更新,还有一个问题是删除缓存后请求会穿透到数据库,而导致性能毛刺的问题。

那么对于这种问题如何解决呢?

如果是mysql数据库,我们可以采用binlog的同步机制来进行全量缓存
如果系统涉及到多数据库,可以采用MQ+同步缓存的方式,类似于mysql的同步机制。
具体的做法是,先对表数据进行全量缓存,当数据库有修改时,对于mysql数据库会自动记录binlog,binlog日志记录了数据库表的所有增删改记录,我们可以通过分析binlog来往缓存数据库进行数据同步的机制进行同步修改,通过binlog的ACK机制来保证事务的最终一致性,来解决数据库的分布式事务问题,MQ的做法也是类似,不过不同的是MQ比mysql实现起来更为复杂,因为数据库和MQ也是异步的,如果保证MQ和数据库的一致性也是需要考虑的问题。

以上方案的缺点是:
1.提高系统了系统复杂性和运维成本
2.因为需要全量缓存,增加了缓存使用量

对于第二点我们可以采用压缩存储的方式进行,以上方案的优点除了可以解决数据库和缓存一致性的问题外还可以利用多机房提供系统可用性,同时由于增加了缓存命中率而消除了性能毛刺,提高了性能,使读取请求基本上可以达到毫秒级。

为了性能缓存没有提供ACID功能,极端情况下也可能丢失数据,解决方式是可以采用数据比对和补偿的方式来对缓存数据进行更新。

高性能写入服务

最初级的解决方案是通过MQ异步写入数据的方式,但是随着数据的日积月累单表的数据会越来越多,如果需要数据查询是一个比较大的问题,那么如何处理呢?

方式一

传统的方式是采用分表分库的方式,一般分表能解决大部分的问题,不到万不得已的情况下一般不建议采用分库来处理,众所周知,分库会带来分布式事务问题,还有跨库查询对于业务来说也是非常大的挑战,不光是性能上会大打折扣,而且运维成本也是几何级别上升。而分表可以在同库进行,不存在分布式事务的问题,同时查询也可以采用union 或者join 方式。

方式二

OLTP+OLAP的终极解决方案,明细数据还是采用MQ的方式异步录入关系数据库,然后将关系数据库的数据通过同步程序同步到比如ES这样的OLAP数据库,即采用读写分离(CQS)的思想,利用关系数据库来保证数据的一致性,利用OLAP数据库体的高性能读取来解决高性能读取问题。

为提高写入的并发量,需要架构提供横向扩展的能力,那么分库是常见的做法,分库一般需要根据业务来决定分库规则,即按什么字段进行分库,做法有很多,这些不在本文的范围,这里想介绍的是在分库异常的情况下如何保证高可用的问题,不卖关子,直接说解决方案,我们可以设计一种无状态存储的方式,写入时随机写入任意分库,最后采用另外一套数据库来存储最终数据,即将随机数据库的内容同步到最终数据库来实现数据的最终写入。

你可能感兴趣的:(如何构建高性能读写服务)