编者按:本文来自微信公众号“嘀嗒嘀嗒”(ID:AngelaTalk),授权36氪发布。作者朱赟(Angela),美国硅谷 Airbnb 的资深工程师。
前两天 Uber post 了一篇文章(参考文末阅读),说他们从 Postgres SQL 转到使用 MySQL 了。blog 写的不错,科普了一些 DB indexing 和 replication 的基本常识。当时转给一个朋友看,朋友说,其实 Uber 2013年才发了一篇文章说他们从 MySQL 转 Postgres SQL。遂去找来看了。看完后寻思下,其实两篇文章背后的情况,两次转型的文章背后的原因,也就可以揣测一二了。
作为两大主流开源数据库,MySQL 和 Postgres 的 “战争” 从来没有停止过,虽然硝烟不似程序语言之间的斗争那么浓烈。你可以去 Quora 或者 Stack Overflow 上搜相关的 MySQL v.s. Postgres 帖子,特别多。我的感觉是,各有各的优势和实用场景,并没有一种比另一种有压倒性优势的存在。
对于大部分程序员来说,公司用哪个 DB,基本不太轮到你来做决定。你加入一个公司的时候,除非是创业公司,或者你是 CTO、VP、Director 级别的,否则大部分的技术选型都应该早已经尘埃落定了的。尤其是 DB,一旦选择,再迁移的代价就很大。所以除非有了颠覆性的优势或者问题,很少有公司会去费时费力做这种大的迁移。而不论是选型还是转型,一个不可忽略的因素,就是你招到的工程师更能驾驭哪一种技术,或者有话语权的决策者们倾向于哪一种技术。这其实和程序语言的选型多少有着异曲同工的类似。
其实 Uber 两次高调转型,类似的事情在 Square 也发生过。虽然 Square 最早是使用 MySQL,但是在大概在 2012 年间,因为 Postgres 的各种优势(如对 geospatial 数据及搜索的支持等),以及当时几位比较 senior 的工程师的大力倡导,很多新的 service 都尝试性地选择了使用 Postgres。所以当时公司的架构是 MySQL 和 Postgres 并存。对于那时候的我而言,不过是有机会学习、了解、和比较两个不同的技术。两者各有特点,有些东西在 MySQL 里似乎更方便,另一些则反之。总有方案去实现,并没有觉得非要哪一种才行。
DB 若安好,便是晴天。
一个公司,如果 DB 从来不出问题,那肯定是因为没有业务或者流量。所有的技术,都有它设计的应用场景。除了一些 happy case,就一定有坑。能够尽可能地避免这些坑,或者在出问题的时候能够最快修复,就成了至关重要的因素。Square 两种 DB 并存的期间,公司里 Postgres 的牛人寥寥无几。但是 MySQL 的 experts,却有几个极为靠谱的。大部分工程师,并不是数据库专家,Postgres 和 MySQL 的相对优势,对我们而言,都比不过出问题的时候有人解惑或者救火来的重要。何况一个公司维系两套同类的数据库系统本身就是个负担。因此,这些使用 Postgres 的 service 后来又都慢慢转成 MySQL 了。
因为我们做支付的需要强 transactional 的支持,所以不太会用 NoSQL 类型的,主要用的还是 MySQL 或者 Postgres。虽说数据库相关的知识和技术,现在工作中因为用得多,慢慢也了解了不少,但如果真的线上出了问题,自己还是不太摆得平。好在每个公司都会有一些数据库大牛,有的公司叫做 DBA。很多中小公司并没有专职的 DBA,都是做系统的人监管。有几位私交甚好。加上自己平时系统里相关问题也经常需要请教,所以一来二去知道了好些好玩的事情。
对数据库大牛我一向是抱景仰的态度的。公司只要稍具规模,数据库这块做不好,基本也就没啥好玩的了。这一块不出问题也罢,一出问题,基本就是见血封喉,网站直接挂掉。那么平时最常见的都有哪些问题呢?
首先就是选型。
每个公司因为业务的不同,数据库系统应用场景不一样,哪一种最合适就不一样。没有哪一个系统一定是最好的。比如做支付的一定要强事务性、一致性的支持,而很多社交平台更多时候其实是需要高可用;有的业务 writes 特别 heavy,有的业务更重要的是 reads;有些业务可以只关心最近几天的数据,因此可以 tradeoff 老数据读写的低效,有的却要频频 access 历史数据;有些业务可以通过加 index 解决 query 效率,有些却只能通过加缓存等等。。这也是为什么很多公司有多个数据库系统并存,以最优化对每个场景和业务的支持。
选型错了,基本就掉在坑里了,也没有频频踩坑一说了。
另外一个就是相关架构。
什么意思呢?这里包括数据库上层的 cache 系统的设计,程序语言对 DB connection 的处理,proxy layer(如果存在)的功能,以及和 binlog 等相关的 data pipeline 的搭建。当然,也包括数据库系统的分区、备份等的具体设计。很多公司早期所有的 table 都在一个 DB 里面,因为各种 connection pool 和 throughput 的限制,这其实基本没法 scale。能够合理的安排不同 table 的分离,让数据相关的留在一起,不相关的或者不太相关的放在另一个 DB 里。类似这些很简单的道理,很多时候却可以很大程度上缓解 scalability 的问题。
而平时我们遇到的最多的问题,还是 human mistake.
再好的系统,使用姿势不对,也是枉然。何况并不是所有的工程师都是数据库专家。
人为错误分成两种。
一种是 DB operation 中犯的错误。这种概率比较低,但是通常危害却最大。几乎所有的公司都会有类似的传奇,常见的版本有:
某某工程师或无意或有意,“不小心” 删掉了数据库某 core table 中所有的数据。不是开玩笑,这种事 Facebook 也发生过,还是一个朋友。好在后来恢复了。这事也成了他的工程师历史上光辉的一笔。
某某工程师做 online schema change 的时候,不小心有一步误操作。结果数据库被 lock 长达几个小时。该公司网站也就挂了好几个小时。
最后这个版本听国内一个大公司的朋友说的,细节还真是不记得了。只是记得两台服务器,做 master slave switch 还是什么的时候,拔错了一个电源插头,然后。。。就没有然后了。
另一种是程序员程序里或者脚本里犯的错误。这个就很常见了。举个很简单的例子。我们知道 Ruby on Rails 对数据库的 access 基本是通过 Active Record 来完成的。Active Record 可以通过一个 connection pool 来限制每个 application 到 DB 的 connection。如果某一个程序或者脚本中的 query 是查询没有被 index 的数据,而导致 full table scan,加上一些 web server 的并行的实现,很经常就会有整个 DB 的所有 connection 被占用,连 kill query 都没法执行。只能人肉的去做一些类似重启的操作。还有更常见的,就是程序里的 N+1 query。这些都很无语,但若说你从没遇到过,那可能是……呵呵。
最后一种,也就是自然流量增长或者流量突增造成的数据库访问瓶颈。
只要是数据库,就有 throughput 的限制。只要你的业务在增长,总有一天数据库访问就会达到一个上限。所以在这个预警到来前,就要做各种 horizontal 或者 vertical 的 scale 来不断提升这个上限。或者是通过缓存等其他机制来对访问量进行分流。这里面可以做的东西就多了。觉得可以单独写一篇了。
另一种就是类似 DDoS、Marketing 等等带来的各种流量的突增。如果是有计划的 Marketing 等,就需要提前做好各种战斗准备。如果是恶意攻击,那就只能靠各种防御工程(如 IP blocking 等等)挡掉这些访问来保证数据库正常工作了。
最后,推荐一个 DBA 写的博客网站内容很精彩,有技术有情怀。文章写的比我好多了。
题图:Mark Bird
参考阅读:
DBA 博客网站(http://dbanotes.net)
为什么Uber转向使用 MySQL(https://eng.uber.com/mysql-migration/)