本文已参与「新人创作礼」活动,一起开启掘金创作之路
大家好,我是桐言无忌,当前是不务正业的攻城狮,信奉“实践出真知,生活更简单”,向往自由。
若有些许启迪、收获,请点个赞,也欢迎大家评论。
继续上个话题
通过上一期,大家已经知道元数据 是怎么玩的了。接下来,为了完成千万级别商品数据存储,以及多样化的查询场景,如何设计存储层就尤为关键。
痛点
总不能还小米加步枪,全程使用MYSQL吧。举个例子,
若是MYSQL存储商品数据,我们要查询颜色是红色,价格是100,品类是衣服,地区是广州的所有商品,那么相对应的sql语句就改这么写: select * from t_goods where 颜色=红色 and 价格=100 and 品类=衣服 and 地区=广州; 若是检索条件更多,and
条件就更多。
且不说这个sql语句可以优化,但就这么去执行,相信性能肯定扛不住。有同学说,那就加索引,可是不能每个字段都加索引啊。另外,别忘了,我们的前提是千万级别的商品数据量,MYSQL理论上说单表能达到1千万,但是,实际试试就知道,查询起来贼慢。
又有同学说了,你可以分库分表呀。针对数据量大,查询慢的情况,这是个办法。但不可避免的增大代码的复杂度,不可取。
来,感觉走到这,MYSQL是蹚到尽头了,不在一棵树上吊着,咱们开阔思路。
咱们是这么玩的
用户查询请求到微服务,微服务组装查询条件到ElasticSearch库里面找到满足条件的商品id列表,再根据商品id列表到Cassandra查询商品详情信息。
这里,我们用到了2种数据库,分别是ElasticSearch和Cassandra。选型它们的原因是什么?
为啥选择ElasticSearch?
选项,也许提到ElasticSearch,第一反应就是“搜索引擎”。有点像百度搜索、京东搜索那种。其实并不然。
ElasticSearch可以做得事情很多,业界主要应用有这么几种:日志实时分析报表、搜索服务、时序数据分析。
我的系统选择,就看中了搜索能力。回顾下我们系统的场景:要做全文检索,类似与拼多多、京东这样电商的大量商品的搜索。优点呢,也很多,列几个主要的:
- 性能贼佳。单个服务最大达到10W的QPS,咱们搜索的商品,总不能一直转圈圈吧。
- 可以有召回率、正确率等指标进行评估改进。
- 生态圈丰富,社区活跃,能找到任何想要的资源。
咱们来看看ElasticSearch的查询语句长啥样:
JAVA api就更方便了。
为啥选择Cassandra?
大家网上搜索,可以搜索出Cassandra的相关信息。我这里选用cassandra,更看重的是它有着MYSQL独有的特长:
-
非常简单的查询语句,支持主键查询。所以我查询商品详情的时候,要带着商品id(主键)。
-
最终一致性。数据到最后总不能对不上号吧。
-
可以存储大量的数据。最喜欢这一点了。
-
可以随时加字段列。我们业务不可能一下子就想好所有字段信息,随着版本开发,是有加字段的需求的。
MYSQL Cassandra 一旦为表定义了某些列,在插入数据时,在每一行中,所有列必须至少填充一个空值 可以随时向任何列族自由添加任何列 关系表只定义列,用值填充表 表包含列,或者可以定义为超级列族 -
java的api特简单。
有了这些,选用cassandra就成了理所当然。
总有点不完美
心细的同学,或许发现,系统中原本是一个MYSQL存储,现在分成了2个ElasticSearch+Cassandra的存储层,那怎么保证两个存储库数据是一致的呢?
确实,两个存储库,入库总有先后之分,那就要想办法保证数据一致性。我们讨论几种场景,看看是哪个场景会出现不一致的情况,好对症下药呀。
- 先写入ElasticSearch失败,or 先写入Cassandra失败,后面的操作都不再执行;这个场景不存在数据不一致的问题。
- 先写入ElasticSearch成功,再写入Cassandra失败,这时候两个库发生了数据不一致。
- 先写入Cassandra成功,再写入ElasticSearch失败,这时候两个库也发生了数据不一致。
对于第2种和第3种场景,其实本质是一致的:不在一个逻辑库上,所以无法保证事务性。
要想保证最终数据一致性的话,我的办法是:记录这次写入失败的商品信息,期待下次回放,重新执行。毕竟失败的是少数,只要保证数据最终一致,系统就是可用的。