我们用一个做手游的故事来聊聊数据层不断优化提升的演进过程。
10:简单设计
有一天,老板突然说做个山寨版的糖果传奇手游,你接到任务后,分析出游戏的交互频率不大,都是点查询,用mysql能简单搞定。对游戏来说,你非常少有机会用orcale这样的上流货。mysql是物美价廉的选择。建个表,设好主键和索引。你轻松搞定数据库设计,满意的泡了杯茶边喝边写程序。
这里说的“点查询”,是指基于指定主键的查询,比如查询指定用户的信息,由于是基于指定主键。查询结果有限且较少。点查询的效率很高。
还有一种叫“面查询”。是基于主键或索引的范围查询,比如查询昨天全部的订单,这样的查询尽管有主键或索引。但结果数量不确定。有时处理不好时会出现严重性能问题。
游戏删档内測上线了,用户数不多。请求的响应也非常及时,老板拍了拍你的肩膀。
100:数据库调优
游戏上线反响不错,精美的画面给了玩家不少惊喜,很多其它玩家蜂拥而入,你从监控系统上发现mysql的压力有点大。当初仅仅是对数据库表结构做了设计,如今你開始review数据库优化了:创建表时默认的MyISAM存储引擎换成InnoDB存储引擎,改动mysql參数加大InnoDB的cache。不使用事务提交。
做了这些优化后,db性能提升明显,整个系统跑得非常欢。你又满意的去泡茶了。
1000:分库分表
你们游戏山寨得比較牛叉。用户持续添加,作为有风险意识的你,肯定不会等到系统告警了才去优化,于是你在想更大訪问量时怎么办?
单台db的性能有极限,必须有扩展到多台db的能力。于是你又一次改动了数据库表结构和后台代码,把主键按规则做了分库分表,眼下用户增长迅猛。假定单台db存放500万用户,终于可能有上亿用户。那么可能有20台DB,于是你分了32个库,每一个库里有32张表,共1024张表。
初始时这1024张表都在一台db上。当用户数添加时。分裂成2台、4台、8台、16台。涉及好分库分表策略后,db压力能通过扩容来解决,你放心了。
关于读写分离
有不少介绍mysql读写分离已提升mysql并发性能的文章。在游戏项目中用得比較少,主要是读写比例的原因。
像站点那种读多写少的应用场景能够採用读写分离,而游戏的读和写差点儿相同多,读写分离的用处不大。并且用户可能是海量的,分多台db是常事,假设分库后再搞读写分离,整个db就过于复杂了。
mysql读写分离是基于mysql主从复制功能的,游戏项目假设对数据安全有要求,通常会用mysql主从复制功能做热备。假设项目有GM或经分系统须要直接查询mysql,往往也是在slave上查询,不直接操作master。避免低效查询减少master性能影响业务。这样的做法也是OLDP(On-Line Transaction Processing。联机事务处理)和OLAP(On-Line Analytical Processing。联机分析处理)分离的常见做法。
10000:缓存
有了分库分表来平滑扩容,项目安稳了较长一段时间,直到某一天。运维说db机器增长比較快,4个月就添加到了64台(master+slave),希望后台能提升单台db的性能。以应对兴许的业务增长。
OK。你祭出你留的后手——memcached,麻利的操起机械键盘,咔哒咔哒的改起后台的代码,增加缓存逻辑:读的时候从memcached读,假设没有就从mysql查询并写入memcached。
写的时候同一时候写入mysql和memcached。
好吧。你最终使用了NoSQL。NoSQL泛指非关系型数据库。是Not Only SQL(有多少人和我一样搞错的~~!)。
搞定这个问题后,成本下降了,项目收入可观,拿奖金好happy。
未完待续~