读写分离和横向扩容那些事

jopen 9年前

前言

文章可能比价浅显,但还是希望大家看过能有共鸣之处

引子

前两天和同事聊天,他问了我一些问题,关于系统设计的。我说,谨记三点,基本上就不大有问题了:

  1. 做好读写分离
  2. 支持横向扩容
  3. 规划好每个服务/模块/类/方法的职责

第三个我就不说了,因为想说也不大能在小篇幅能说好。

1,2两点很重要。很多初创公司或者小公司,一般都是先把功能实现了再说,但我认为一个好的系统设计师,或者程序员,都应该做到:

  • 让系统支持读写分离,横向扩容
  • 设计时留下退路,让系统非常容易支持

为什么这么说呢,因为我看到了不少创业公司,甚至包括我们公司部分产品,一开始不考虑这些,接着开始遇到性能问题,这个时候才开始想到要做读写分离之类的功能,但是改起来比较困难,要动大手术,而产品已经积累了大量用户和内容,如果是新功能增加还好,像这种大改动,研发还是很忌惮的。所以就会想办法拖着,譬如添加各种缓存,来缓解性能和扩展性问题。而随着功能越来越多,势必会让性能进一步下降。

横向扩容在某些程度和读写分离有比较紧密的关系,一般如果做了读写分离,那么很多情况横向扩容也就自然是水到渠成的,所以我这里重点讲的是如何做好读写分离

如何做好读写分离

我们现在和产品的对接过程中,所有数据写入的是一套流程,所有查询的是另一套流程,而且是由不同的服务群集组成,所以天然实现了读写分离,并且能够很好的支持了横向扩容。

所以我对数据库读写分离没有做过太多工作,但很多东西是相同的,我这里只是提提自己的看法。

读写分离说起来容易,其实做起来也有些麻烦,往往一个读的逻辑环节(外部看来),其实也会有大量的写。最简单的例子是,我阅读一篇文章,文章阅读数会变更(姑且认为是写数据库),会记录最近访问用户等。也就是从功能意义上来看,读和写往往是混合的,

这里就会有三套很直观的方案:

  1. 在数据层面区分读写,应用发现是update,insert等操作就走主库,如果是select 就走从库
  2. 做一个proxy,该proxy 拦截所有sql,具体功能类似1所说的。
  3. 对写单独做一个服务,提供写API。

三种方案都基于数据库的主从结构。类似:

数据库

  1. master
  2. slave-1~slave-n

其中第三种具体方案如下:

应用层,则要分为读服务和写服务。 应用 master 只负责和数据库master打交道,并且只负责写操作。应用的slave则可多个对应一个数据库slave就行。

应用slave 涉及到任何写数据库的部分,则转换为调用应用master提供的API服务,其实就是把写库操作服务API化了。

大概结构如下:

对我而言,肯定是偏向3的方案。为什么?因为我们要看到最后架构的演化方向。一个系统不管是因为功能复杂了,还是为了易于扩展,最终都会是一个系统由N个服务组合起来的,不会是一个单单的进程就完成的。

通常来说,读写分离是系统服务模块化的前兆。这个时候我们的系统其实由原来的单一系统演化出来了一个单独的写服务。随着压力上升及时是写服务无我们可能也会划分成多个服务,读的部分就更不用说了。

加入设计一个博客系统读写分离时,可这样操作:

  1. 所有写操作由master实现API化
  2. 每个slave是一个正常的博客应用,接受读和写,只是内部写的时候,不写数据库,而是调用master API

对于现有系统的改造做读写分离也比较简单:

  1. 新建一个master项目,实现写操作API化
  2. 原有的程序,将所有写数据库操作都转化成对master API的调用

横向扩容

读的横向扩容比较好做,某些情况可能需要注意将session会话粘滞在一台服务器上。

对于写的横向扩容,我们现在的做法是,通过消息队列 ,可参看我这篇关于消息队列应用场景的介绍文章 大数据技术栈-Web框架&消息队列,所有写的动作都会发布到消息队列,然后通过后端起服务消费消息队列执行真正写的动作。所以后端是可以任意起多个服务的。在数据产品中,这个后端服务其实叫数据链路处理服务。主要执行类似ETL一类的工作,进行规整化后存入索引,HBase,Redis等存储器中。

好处是什么

  1. 读写分离是能横向扩容的基础
  2. 其实读写分离本质上是模块化,系统解耦
  3. 系统扩展性好,可以充分利用云时代扩充服务器的便利。
  4. 上线(更新)可以实现不中断服务。我们现在就是rolling update(有点类似灰度发布),所以能感觉到它的好。

    切掉A服务器流量 -> 更新服务 -> 测试 -> 切回A服务器流量 -> 监控查看 -> 依次升级所有服务器

题外话一下,别小看上线更新发布,如果你做的不是项目,而是一个一直用的产品,系统设计能给上线带来方便的话,真是一件功德无量的事情。 

最后的话

前面也提到了,为什么采用方案3,读写分离是第一步,其实最后我们的目标可能还是会把一个服务拆成N个服务,协同运作。理论都是通的,这就好比这些年规模PC服务器取代中小型机是一样的。

来自:http://weibo.com/p/1001603835554767706247