重新架构:从 Redis 到 SQLite 性能提升

在这篇博文中,他们用 SQLite 取代了 Redis,而令人惊讶的是,SQLite 的速度更快!有趣的是,Redis 是在本地运行,而 SQLite 是将数据存储在磁盘上。因此,这是内存(Redis)与磁盘(SQLite)的较量,但 Redis 需要通过 IPC 进行通信。

人们一直以为磁盘 I/O 比 IPC 慢,但显然这并不总是正确的!实际上,IPC 也可能更慢!Redis自己也承认这点

Wafris重新架构了它的系统,从Redis迁移到SQLite,以提高简单性和性能。这篇博客文章详细介绍了为什么SQLite更适合他们的需求,重点是它如何简化缓存和优化网站性能。如果你对网络安全和流量管理的架构决策感兴趣,这篇文章提供了一个实用的视角,看看他们为什么做出了转变。

背景

我们是 Wafris,一家开源 Web 应用程序防火墙公司,除其他框架外,还提供 Rails 中间件客户端。

在发布时,v1 客户端需要将本地 Redis 数据存储与您的应用一起部署。我们现在发布了使用 SQLite 作为后备数据存储的 Rails 客户端 v2。

本文介绍了我们从 Redis 迁移到 SQLite 时的决策、性能考虑因素和架构变更。如果您对我们为客户(已部署的中间件)从 Redis 迁移到 SQLite 时的决策感兴趣,请继续阅读本文

总结

  • SQLite 有其优点,也有其缺点。

  • Redis 有其优点,也有其缺点。

  • 传统的 RDBMS(Postgres/MySQL)有其优点和缺点。

这些数据存储并非直接替代,如果您尝试这样做,您将会遇到麻烦。本文介绍了将基于 Redis 的 v1 客户端重新架构为基于 SQLite 的 v2 客户端时进行的测试和决策。

什么导致了这一改变?

自 Wafris 成立的第一天起,我们的目标就是让开发人员尽可能轻松地保护他们的网站。

但我们的 v1 在兑现这一承诺方面取得了好坏参半的结果。我们当时认为,用用户拥有的(自带的)Redis 数据存储来支持 Wafris 客户端是一个明智的选择。

部分原因是我们是在 Heroku 生态系统中成长起来的,在这里 Redis 只需点击一下即可启动,并且部署方式也便于远程访问。我们还研究了 Sidekiq 等具有类似模型的成功项目。

但生态系统远不止于此,我们的许多用户都遇到了难以调试和修复的 Redis 部署问题。

换句话说,如果我们试图让您轻松一些,我们不应该在此过程中随便让您成为 Redis 数据库管理员。

什么是速度?

尽管与传统的 RDBMS 相比,Redis 很"快",但它仍然是一个需要管理连接、内存、进程等的数据库,这会给堆栈带来更多的脆弱性(与我们想要实现的目标相反)。

最重要的是,如果您处于云环境中,那么您需要考虑网络延迟。网络延迟对我们来说是个大问题,因为必须根据 Wafris 中存储的规则评估您应用的每个入站 HTTP 请求。因此,尽管我们付出了艰辛的努力和编写代码以尽可能快地获得 v1 客户端,但我们经常会遇到这样的情况:尽管我们尽了最大努力,但由于应用所配置的网络速度很慢,我们仍然会减慢应用的速度。

整体式假设

虽然确实存在完全分布式的应用程序,并且大多数 Rails 应用程序都是"庞大的整体"(tm?我不知道,不要起诉我),但我们发现很多分布式应用程序扰乱了我们的假设。

部署到多个区域的应用程序、将功能拆分为具有重叠职责的服务器的应用程序或仅部分使用 Rails 并与其他语言或框架一起部署的应用程序。

大多数情况下,生产中的事情并不是那么干净,这给使用 Redis 带来了更多的摩擦。

迫使我们重新思考我们的架构

Wafris 是一款 Web 应用程序防火墙。在 Rails 中,它作为中间件安装。它允许您设置"阻止 IP 1.2.3.4"之类的规则,然后当有人请求您的网站时,您会根据这些规则评估该请求。

想象一下这个简化的两步过程:

  1. 将 HTTP 请求与规则进行比较(如果匹配 == 403,否则为 200)

  2. 报告处理(阻止、允许、通过)

从抽象角度来说,这是对数据库中规则的配对"读取"(步骤 2),然后"写入"报告,详细说明对该请求及其数据所执行的操作。

从逻辑角度来看,这个过程的前半部分"读"比后半部分"写"重要得多:

  • 读取(又称"请求")需要按顺序处理
  • 必须对请求进行过滤,否则不良请求可能会通过
  • 读取(又称"请求")对时间敏感,因为它们会影响用户感知的网站性能。
  • 写入(又称"报告")可以以较慢的速度、批量的、异步的等等方式完成。

输入 SQLite

其他人对 SQLite 的适用范围的描述比我自己写的更加详细,因此关于这个话题,我将向您推荐以下资源:

Aaron Francis 的"高性能 SQLite"课程,网址为https://highperformancesqlite.com/

Stephen Margheim 的"SQLite on Rails"------如何以及为何实现最佳性能

Oldmoe- https: //oldmoe.blog/

SQLite 对 Wafris 有何好处?

如上所述,我们的主要瓶颈是网络 IO,Stephen 提到了 SQLite 文档中的这句话:"SQLite 不与客户端/服务器数据库竞争。SQLite 与 fopen() 竞争。"

理论上,这应该比仅基于切断网络往返的 Redis 解决方案快得多。

因此,我们决定对 SQLite 与 Redis 进行基准测试。

SQLite 和 Redis 的基准测试

基准测试是一门用高度精确的数字欺骗自己的黑暗艺术。

而对数据存储进行基准测试则更加困难。我见过的每一个翻转数据库基准测试都被一层星号和限定词所覆盖,HN 上的评论充满了"如果你在编译时设置这个标志,你的读取速度就会提高 3%,而运行这个的人没有这样做这一事实证明他们得到了贿赂,并且他们积极出售疯狂的游艇摇滚 Harambe 模因的阴暗 NFT 骗局。

测试是在我的本地 Macbook Air M2 上进行的,并使用自制的 Redis 和本地 SQLite db 进行安装。

  1. 我们针对现有范围数据集(120 万个条目)进行了测试
  2. 然后以相同的顺序针对 SQLite 和 Redis 运行多组 IP。
  3. 在每个倍数下,我们都运行了 5 次测试并取平均值。

结果:

  • SQLite 击败 Redis

与本地部署的 Redis 实例相比,SQLite 的速度大约提高了 3 倍。YMMV。再次注意,这是在考虑任何网络延迟之前。

从我们的角度来看,这是一个非常棒的结果,因为即使 SQLite 仅在本地与 Redis 相当,我们仍然能够通过完全缩短网络时间而获胜。

构建同步架构

在 v1(Redis)上,更新循环如下所示:

  1. 用户在 Wafris Hub 中更新规则("阻止 IP 1.2.3.4")

  2. Wafris Hub 更新 Redis 数据存储中的规则

这显然不适用于 SQLite,因为我们无法将 SQLite 数据库"推送"到 Web 服务器。有一些较新的 SQLite 即服务提供商允许您执行此版本,但出于各种成本、性能和安全考虑,它对我们来说不起作用,因为我们仍然需要个人用户来部署它们、打开端口、允许入站连接等。

在 v2(SQLite)上,更新循环如下所示:

  1. 用户在 Wafris Hub 中更新规则("阻止 IP 1.2.3.4")

  2. 每隔一段时间(时间或请求次数),客户端会检查更新的规则

  3. 如果规则更新,客户端将下载一个全新的 SQLite 数据库

这很有效,因为它消除了用户的大部分安装和配置责任。

我们发现 v2 客户端的成功安装量增加了约 3 倍。

总之

我们对使用 SQLite 的 v2 架构非常满意。它已经帮助许多网站抵御了攻击并保持在线。

它变得更容易使用,我们需要的支持工作更少,用户的麻烦也更少,我们认为这对于更安全、更有保障的互联网来说是一个胜利。

https://www.jdon.com/75708.html

相关推荐
CodeClimb1 小时前
【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
光头程序员4 小时前
grid 布局react组件可以循数据自定义渲染某个数据 ,或插入某些数据在某个索引下
javascript·react.js·ecmascript
fmdpenny5 小时前
Vue3初学之商品的增,删,改功能
开发语言·javascript·vue.js
小美的打工日记5 小时前
ES6+新特性,var、let 和 const 的区别
前端·javascript·es6
涔溪5 小时前
有哪些常见的 Vue 错误?
前端·javascript·vue.js
程序猿online5 小时前
前端jquery 实现文本框输入出现自动补全提示功能
前端·javascript·jquery
Turtle7 小时前
SPA路由的实现原理
前端·javascript
HsuYang8 小时前
Vite源码学习(九)——DEV流程中的核心类(下)
前端·javascript·架构
傻小胖8 小时前
React 中hooks之useInsertionEffect用法总结
前端·javascript·react.js
蓝冰凌9 小时前
【整理】js逆向工程
javascript·js逆向