http://www.infoq.com/cn/presentations/9-months-achieve-large-number-users-scalable-architecture
http://segmentfault.com/a/1190000002924334
在不同阶段选择最适合自己的方案
http://segmentfault.com/a/1190000000383231
http://segmentfault.com/a/1190000002924334
在不同阶段选择最适合自己的方案
首先先从架构上来说,看下美拍经历的几个阶段:
- 极简化设计(快速发布上线)
- 保持简单行设计(产品快速迭代)
- 可扩展和高可用保证(用户量到一定量级)
- 高可扩展和高可用保证
然后我们来看下美拍一路走来遇到的问题:
- MySQL慢查询
- MySQL写入瓶颈
- redis超时
- memcached命中率奇低
- 服务相互依赖
- 监控报警不稳定
- CDN服务各种故障
- 添加字段成本高
- 量级上来后,MySQL继续慢
然后,我们按服务维度把每一个服务拆开,看下每一个服务在美拍架构上的迭代过程。
一、MySQL
MySQL是最重要的一个服务,在美拍架构里经历了多次迭代。在第一版直接就是一个实例,为了保持代码的简单,业务逻辑能在数据库里做的都放到数据库做了,比如Feed功能,直接用MySQL的join查询。
但是后来就出现了一些慢查询的情况,这时候做了主从,做读写分离,多个从库用来做查询。再到后来出现写入也慢的情况,这时候也没有做架构上的优化,而是升级硬件,因为现在正是业务高速发展阶段,需要极简化设计,这个阶段更多精力要放在业务开发上(估计当时也木有招到合适的人:))。
过了一段时间又开始出现写入慢的情况,这时候才开始做分表。但是等到了重心放在扩展性和可用性上时,又遇到了新的问题,一个很大的问题还是写入慢,另外一个就是随着数据量的增大,添加字段成本特别的高。针对这两个问题做了下面两个方案:
- 异步写入,做到前端永远可写,后面复杂的事情放到队列里面去异步的做
- 索引和数据分离,把需要索引的字段单独拆出来一个表,其他数据用kv存储,value就是所有属性和值的pb二进制数据,解决家字段困难的问题
这个时候针对MySQL的架构优化才告了一段落 :)
二、缓存
缓存主要用到了memcache和redis(redis应该主要是用在队列和计数服务)。在量比较小的时候就是简单粗暴的用,但是很快就遇到了redis超时的问题,这时候对redis扩容,使用多slave架构。然后是rdb dump时影响用户请求的问题,解决方法一是在凌晨访问量低的时候才去dump,二是用不对外服务的机器来做dump。
然后memcached遇到了命中率很低的问题,一个大问题就是容量瓶颈,这没啥好说的,扩容(小军有提到,要随时做好扩容的准备)。另外一个就是slab calcification的问题(又叫slab钙化问题,这个是memcached的内存分配机制导致的,简单来说就是memcached会内存分成N个slab,当新添加一个内存对象时会根据这个对象的大小来选择不同的slab,如果没有合适的就会创建一个slab,那如果这时候剩余内存不足以分配一个slab呢?这时候就出现了钙化问题了),美拍当时的解决办法是核心业务隔离部署,避开这个问题。
到可用性保证阶段,缓存的可用性就更加的非常的重要了,缓存挂了可能就整个系统都挂了,很难收场,所以就要保证缓存的可用性。这时候做了主从的优化,master也承担读查询,以保证缓存热度,slave穿透到master,master穿透到slave,防止单点故障。
三、运维
在初期只是简单的监控告警,有时候出问题了可能收不到告警或者看不到是啥地方出问题,后来逐渐完善监控告警,且监控告警是用配置比较高的服务器,保证监控告警的可用性。然后假如更多监控维度和更多日志,方便定位问题。对依赖的第三方服务和资源做开关,出问题时可以通过服务的开关保证核心路径可用。
四、第三方服务
主要提到的是CDN服务。其中一个很大的问题就是DNS被攻击、被劫持,除了和运营商保持沟通外,还做了多服务商配合的策略,比如同样的数据在多个云服务那里做冗余,客户端在访问时如果出现问题就切换到其他的访问地址,并且在客户端做了服务端可用性探测。这也是个非常有价值的经验。
五、技术栈
整个看下来会发现美拍的架构做的非常的稳,小军也有提到,在项目初期高速发展阶段做架构时要克服对完美架构的欲望、克服对新技术的欲望,先让系统跑起来。
但是在整个迭代过程中,美拍也一直在引入新技术,比如在团队不太熟悉时先在部分业务上使用MongoDB,在注重可扩展和可用性阶段,引入java做业务逻辑,引入c做底层基础服务。