如何停止担忧并开始没有巨石的生活

如何停止担忧并开始没有巨石的生活

我们都喜欢故事。 我们喜欢坐在火边谈论我们过去的胜利、战斗,或者只是我们的工作经验。

今天就是这样的一天。 即使您现在不在火场,我们也有一个故事给您。 我们如何开始在 Tarantool 上使用存储的故事。

曾几何时,我们公司有几块“巨石”和一个“天花板”,这些巨石正在缓慢但坚定地逼近,限制了我们公司的飞翔和发展。 我们有一个清晰的认识:有一天我们会严重触及这个上限。

现在流行的意识形态是从设备到业务逻辑,将一切和每个人分开。 因此,例如,我们有两个在网络级别实际上独立的 DC。 然后一切就完全不同了。

如今,有很多以 CI/CD、K8S 等形式进行变革的工具和工具。 在“铁板一块”的时代,我们不需要那么多外来词。 只需更正数据库中的“存储”就足够了。

但随着时间的推移,请求的数量也随之增加,有时 RPS 超出了我们的能力。 随着独联体国家进入市场,第一块巨石的数据库处理器的负载没有降到90%以下,RPS保持在2400的水平。这些不仅仅是小型选择器,而是大量的查询。一堆检查和 JOIN 可以在大 IO 的背景下运行几乎一半的数据。

当全面的黑色星期五促销活动开始出现时——而 Wildberry 是最早在俄罗斯举办促销活动的公司之一——情况变得非常糟糕。 毕竟这样的日子负载量会增加三倍。
哦,这个“单一时代”! 我相信你也经历过类似的事情,但你仍然无法理解为什么这种事会发生在你身上。

你能做什么——时尚是技术所固有的。 大约 5 年前,我们不得不以 .NET 和 MS SQL Server 上现有站点的形式重新考虑这些 mod 之一,该站点仔细存储了站点本身的所有逻辑。 我小心翼翼地保存着它,以至于锯开这样一块巨石变成了一种漫长而不易的乐趣。
一个小题外话。

在各种活动中我都会说:“如果你没有看到一块巨石,那么你就没有成长!” 我很想知道你对此事的看法,请写在评论中。

有一声雷霆

让我们回到我们的“篝火”。 为了分配“整体”功能的负载,我们决定将系统划分为基于开源技术的微服务。 因为,至少,它们的扩展成本更便宜。 我们 100% 理解我们必须扩大规模(而且规模很大)。 毕竟,那时就已经可以进入邻国市场,并且注册数量以及订单数量开始更加强劲地增长。

在分析了从单体架构转向微服务的第一批候选者之后,我们意识到其中 80% 的编写来自后台系统,而读取来自前台系统。 首先,这涉及到我们的几个重要子系统——用户数据和基于额外客户折扣和优惠券信息计算商品最终成本的系统。

缩进。 现在想象起来很可怕,但除了上述子系统之外,产品目录、用户购物车、产品搜索系统、产品目录过滤系统和各种推荐系统也从我们的整体中删除了。 对于它们每个人的操作,都有不同类别的狭隘定制系统,但曾几何时,它们都住在一个“房子”里。

我们立即计划将客户的数据传输到分片系统。 取消计算商品最终成本的功能需要良好的读取扩展性,因为它产生的RPS负载最大,并且对数据库来说最难实现(计算过程中涉及大量数据)。

结果,我们想出了一个非常适合 Tarantool 的方案。

当时对于微服务的运行,选择了在虚拟机和硬件机上与多个数据中心配合的方案。 如图所示,Tarantool 复制选项适用于主-主和主-从模​​式。

如何停止担忧并开始没有巨石的生活
建筑学。 选项 1. 用户服务

目前有24个分片,每个分片有2个实例(每个DC一个),均为master-master模式。

数据库之上是访问数据库副本的应用程序。 应用程序通过我们的自定义库与 Tarantool 配合使用,该库实现了 Tarantool Go 驱动程序接口。 她可以看到所有副本,并且可以与主副本一起读写。 本质上,它实现了副本集模型,添加了用于选择副本、执行重试、断路器和速率限制的逻辑。

在这种情况下,可以在分片的上下文中配置副本选择策略。 例如,循环赛。

如何停止担忧并开始没有巨石的生活
建筑学。 选项 2. 计算货物最终成本的服务

几个月前,大多数计算商品最终成本的请求都发送给了一项新服务,该服务原则上无需数据库即可运行,但不久前,所有内容都由 Tarantool 底层的服务 100% 处理。

服务数据库由 4 个主站组成,同步器将数据收集到其中,每个复制主站将数据分发到只读副本。 每个主节点大约有 15 个这样的副本。

无论在第一种方案还是第二种方案中,如果一个DC不可用,应用程序可以在第二个DC中接收数据。

值得注意的是,Tarantool 中的复制非常灵活,可以在运行时进行配置。 在其他系统中,出现了困难。 例如,更改 PostgreSQL 中的 max_wal_senders 和 max_replication_slots 参数需要重新启动向导,这在某些情况下可能会导致应用程序和 DBMS 之间的连接断开。

搜索并找到!

为什么我们不“像正常人一样”去做,而是选择了一种非典型的方式? 这取决于什么被认为是正常的。 许多人通常从 Mongo 构建一个集群并将其分布在三个地理分布式 DC 上。

当时我们已经有两个Redis项目了。 第一个是缓存,第二个是用于不太关键数据的持久存储。 他的处境相当困难,部分原因是我们的错。 有时,关键的体积很大,并且该站点有时会变得不舒服。 我们在主从版本中使用了这个系统。 而且有很多情况是master出了问题导致复制崩溃的。

也就是说,Redis 适合无状态任务,而不适合有状态任务。 原则上,它可以解决大多数问题,但前提是它们是具有一对索引的键值解决方案。 但当时的Redis在持久化和复制上是相当可悲的。 此外,还有关于性能的抱怨。

我们考虑了 MySQL 和 PostgreSQL。 但第一个产品不知为何没有引起我们的注意,而第二个产品本身就是一个相当复杂的产品,在其上构建简单的服务是不合适的。
我们尝试了 RIAK、Cassandra,甚至图形数据库。 这些都是相当小众的解决方案,不适合作为创建服务的通用工具。

最终我们选择了 Tarantool。

我们在 1.6 版本时转向了它。 我们对它感兴趣的是键值对和关系数据库功能的共生。 还有二级索引、事务和空间,这些就像表一样,但并不简单,你可以在其中存储不同数量的列。 但 Tarantool 的杀手级功能是与键值和事务性相结合的二级索引。

反应灵敏、随时准备在聊天中提供帮助的俄语社区也发挥了作用。 我们积极使用这一点并直接在聊天中进行直播。 并且不要忘记体面的坚持,没有明显的失误和错误。 如果你看看我们使用 Tarantool 的历史,我们在复制方面遇到了很多痛苦和失败,但我们从未因为它的错误而丢失数据!

实施起步艰难

当时,我们的主要开发堆栈是 .NET,Tarantool 没有连接器。 我们立即开始用 Go 做一些事情。 它与 Lua 也运行良好。 当时的主要问题是调试:在 .NET 中一切都很好,但之后就很难投入嵌入式 Lua 的世界了,因为除了日志之外没有任何调试。 此外,由于某种原因,复制会定期崩溃,因此我必须深入研究 Tarantool 引擎的结构。 聊天对此有所帮助,在较小程度上,文档也有所帮助;有时我们会查看代码。 那时,文档马马虎虎。

因此,在几个月的时间里,我设法头脑清醒,并通过与 Tarantool 的合作获得了不错的结果。 我们编译了 git 的参考开发,有助于形成新的微服务。 例如,当出现一个任务:创建另一个微服务时,开发人员查看存储库中参考解决方案的源代码,只花了不到一周的时间就创建了一个新的微服务。

这是一段特殊的时期。 按照惯例,你可以去找邻桌的管理员询问:“给我一个虚拟机。” 大约三十分钟后,车就到了。 您自己连接,安装了所有内容,然后流量就发送给您了。

如今,这将不再有效:您需要向服务添加监控和日志记录、通过测试覆盖功能、订购虚拟机或交付给 Kuber 等。 一般来说,这样会比较好,虽然时间会比较长,也比较麻烦。

分而治之。 和Lua有什么关系?

存在一个严重的困境:一些团队无法可靠地推出对 Lua 中包含大量逻辑的服务的更改。 这通常伴随着服务不起作用。

也就是说,开发者正在准备某种改变。 Tarantool 开始进行迁移,但副本仍使用旧代码; 一些 DDL 或其他东西通过复制到达那里,代码就会崩溃,因为它没有被考虑在内。 结果,管理员的更新流程就写在A4纸上:停止复制,更新这个,打开复制,这里关闭,那里更新。 恶梦!

因此,现在我们通常尝试在 Lua 中什么都不做。 只需使用 iproto(一种用于与服务器交互的二进制协议)即可。 也许这是开发人员缺乏知识的原因,但从这个角度来看系统是复杂的。

我们并不总是盲目地遵循这个脚本。 今天我们没有黑白分明:要么一切都在 Lua 中,要么一切都在 Go 中。 我们已经了解如何将它们结合起来,这样我们就不会在以后出现迁移问题。

塔兰图尔现在在哪里?
该服务中使用 Tarantool 计算商品的最终成本,并考虑折扣优惠券(也称为“Promoter”)。 正如我之前所说,他现在即将退休:他将被一项预先计算价格的新目录服务所取代,但六个月前所有计算都是在 Promotizer 中进行的。 此前,其一半逻辑是用Lua编写的。 两年前,该服务被变成了一个存储设施,并且用 Go 重写了逻辑,因为折扣机制发生了一些变化,并且该服务缺乏性能。

最关键的服务之一是用户配置文件。 也就是说,所有的Wildberry用户都存储在Tarantool中,大约有50万个,按照用户ID进行分片的系统,分布在连接Go服务的多个DC上。
根据 RPS 的数据,Promoter 曾经是领先者,达到了 6 个请求。 一度我们有 50-60 份。 现在RPS的领先者是用户个人资料,大约有12万个。该服务使用自定义分片,按照用户ID的范围进行划分。 该服务服务于20多台机器,但这太多了;我们计划减少分配的资源,因为4-5台机器的容量就足够了。

会话服务是我们在 vshard 和 Cartridge 上的第一个服务。 设置 vshard 和更新 Cartridge 需要我们付出一些努力,但最终一切顺利。

用于在网站和移动应用程序中显示不同横幅的服务是直接在 Tarantool 上发布的首批服务之一。 该服务值得注意的是,它已有 6-7 年历史,仍在运行且从未重新启动过。 使用了主主复制。 没有任何东西被破坏过。

有一个在仓库系统中使用 Tarantool 进行快速参考功能的示例,以便在某些情况下快速复核信息。 我们尝试使用 Redis 来实现此目的,但内存中的数据比 Tarantool 占用更多空间。

Tarantool 还提供候补名单、客户订阅、当前流行故事和延期商品等服务。 最后一个服务占用内存约120GB。 这是上述服务中最全面的服务。

结论

由于二级索引与键值和事务性相结合,Tarantool 非常适合基于微服务的架构。 然而,当我们对 Lua 中包含大量逻辑的服务进行更改时,我们遇到了困难 - 服务经常停止工作。 我们无法克服这个问题,随着时间的推移,我们找到了 Lua 和 Go 的不同组合:我们知道在哪里使用一种语言,在哪里使用另一种语言。

关于该主题还可以阅读什么

来源: habr.com

添加评论