简介

 Readyset 是一种轻量级缓存解决方案,利用内存来存储缓存数据,实现复杂的 SQL 闪电般快速查询。 

Readyset 介于应用程序和数据库之间,是一个Cache层。相当于Redis/Memcached的作用,但它不需要更改你的一行代码。


架构

Java/PHP应用程序 -> Readyset -> MySQL数据库

Readyset 是 MySQL 轻量级缓存解决方案_缓存

Readyset 的工作流程如下:

  1. 对于读操作:
  • 您直接向 Readyset 发送 SQL 查询。
  • 如果结果已缓存,Readyset 会即时返回,实现亚毫秒级响应。
  • 若未缓存,Readyset 会将请求转发至后端数据库,获取结果后缓存并返回。


  1. 对于写操作(INSERT、UPDATE、DELETE):
  • Readyset 会直接将请求转发至后端数据库执行,并相应更新其缓存。


Readyset 的优势在于:

  • 使用标准 SQL 即可访问,无需学习新的查询语言
  • 无需修改应用程序代码,只需更改数据库连接字符串
  • 支持复杂 SQL 查询的高速缓存
  • 自动保持缓存与数据库的一致性
  • 可选择性地缓存高频查询,优化资源利用

这种设计使 Readyset 特别适合读密集型应用,能显著提升查询性能,同时保持操作的简便性和数据的最终一致性。


安装与使用

1.下载Readyset Docker 镜像

shell> docker pull readysettech/readyset
  • 1.


2.运行 Readyset 服务

shell> docker run -d -p 3307:3307 -p 6034:6034                      \
--name readyset                                                     \
-e UPSTREAM_DB_URL=mysql://admin:123456@192.168.137.131:6666/test   \
-e LISTEN_ADDRESS=0.0.0.0:3307                                      \
readysettech/readyset:latest                                        \
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

注:UPSTREAM_DB_URL参数值填写后端MySQL的用户名,密码,IP地址,端口号,数据库名。

# docker ps -a
CONTAINER ID   IMAGE                          COMMAND                   CREATED       STATUS   
    PORTS                                                                                  NAMESf97818f52261   readysettech/readyset:latest   "/usr/local/bin/read…"   6 hours ago   Up 6 hours
   0.0.0.0:3307->3307/tcp, :::3307->3307/tcp, 0.0.0.0:6034->6034/tcp, :::6034->6034/tcp   readyset[root
  • 1.
  • 2.
  • 3.
  • 4.

Readyset 暴露了两个端口: 3307 和 6034。 Readyset 进程将在 3307 端口监听查询流量,并通过 /metrics 端点在 6034 端口发送监控数据。 

然后,Readyset 将连接到您的数据库,并复制指定的表(即所有表或明确定义的表)。 根据这些表的大小以及 Readyset 和数据库之间的网络连接情况,这可能需要几秒到几小时的时间。

要检查表格是否已导入,请执行以下操作:

shell> docker logs readyset
  • 1.

当你看到:INFO replicators::noria_adapter: MySQL connected代表已准备好开始缓存查询。

或者,你用MySQL客户端访问3307端口,执行SHOW READYSET STATUS命令:

mysql> SHOW READYSET STATUS;
+----------------------------+---------------------------+
| Variable_name              | Value                     |
+----------------------------+---------------------------+
| Database Connection        | Connected                 |
| Connection Count           | 1                         |
| Snapshot Status            | Completed                 |
| Maximum Replication Offset | mysql-bin.000009:34960586 |
| Minimum Replication Offset | mysql-bin.000009:34610809 |
| Last started Controller    | 2024-08-19 01:28:48 UTC   |
| Last completed snapshot    | 2024-08-19 01:28:48 UTC   |
| Last started replication   | 2024-08-19 01:28:48 UTC   |
+----------------------------+---------------------------+
8 rows in set (0.62 sec)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

查看该Snapshot Status列。如果快照成功完成,它将报告Completed

现在 Readyset 已准备好开始缓存查询。


3.在 Readyset 中缓存查询

用MySQL客户端连接上3307端口(Readyset端口),将线上的慢SQL在 Readyset 里运行,并执行SHOW PROXIED QUERIES命令

mysql> SHOW PROXIED QUERIES;
+--------------------+------------------------------------------------------------------------------------------------+--------------------+-------+
| query id           | proxied query                                                                                  | readyset supported | count |
+--------------------+------------------------------------------------------------------------------------------------+--------------------+-------+
| q_4c1cf3b8080fe634 | SELECT * FROM `test`.`t1` JOIN `test`.`t3` ON (`t1`.`id` = `t3`.`id`) WHERE (`t1`.`name` = $1) | yes                |     0 |
| q_906fa3045243ea2f | desc t1                                                                                        | unsupported        |     0 |
| q_ce39192051ca85ed | SELECT DATABASE()                                                                              | unsupported        |     0 |
| q_7da7d6ae3e899256 | SELECT count(*) FROM `t1` WHERE `id` IN (SELECT `id` FROM `t3`)                                | unsupported        |     0 |
| q_95e54bea818ecaa6 | SELECT count(*) FROM `t1`                                                                      | unsupported        |     0 |
| q_c4546a3773bfb40c | SELECT * FROM `test`.`t1` JOIN `test`.`t3` ON (`t1`.`id` = `t3`.`id`)                          | unsupported        |     0 |
| q_29a1660186d5c04b | SELECT * FROM `t1`                                                                             | unsupported        |     0 |
| q_9688f018b86e697b | SELECT * FROM `t3`                                                                             | unsupported        |     0 |
| q_adbda9f38a04a705 | SELECT * FROM `test`.`t1` JOIN `test`.`t3` ON (`t1`.`id` = `t3`.`id`) WHERE (`t1`.`cid` = $1)  | pending            |     0 |
+--------------------+------------------------------------------------------------------------------------------------+--------------------+-------+
9 rows in set (0.00 sec)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

观察readyset supported列,如果为Yes,代表该SQL支持缓存。如果值处于待定状态,请再次检查,直到看到是或否。 如果数值等待超过 15 秒,则不支持查询。


4.创建SQL缓存

要缓存查询,请使用:

CREATE CACHE FROM <query id>;
  • 1.

这里以q_4c1cf3b8080fe634为例

mysql> CREATE CACHE FROM q_4c1cf3b8080fe634;
Query OK, 0 rows affected (0.68 sec)
  • 1.
  • 2.


5.查看缓存查询

mysql> SHOW CACHES\G;
*************************** 1. row ***************************
         query id: q_36d53f6aa2b555c8
       cache name: q_36d53f6aa2b555c8
       query text: SELECT `test`.`t1`.`id`, `test`.`t1`.`name`, `test`.`t3`.`id`, `test`.`t3`.`jdoc` FROM `test`.`t1` JOIN `test`.`t3` ON (`test`.`t1`.`id` = `test`.`t
3`.`id`) WHERE (`test`.`t1`.`id` = $1)fallback behavior: fallback allowed
            count: 0
*************************** 2. row ***************************
         query id: q_c50ffddbdedb51f0
       cache name: q_c50ffddbdedb51f0
       query text: SELECT count(*) FROM `test`.`title_ratings` JOIN `test`.`title_basics` ON (`test`.`title_ratings`.`tconst` = `test`.`title_basics`.`tconst`) WHERE (
(`test`.`title_basics`.`startyear` = $1) AND (`test`.`title_ratings`.`averagerating` > 5))fallback behavior: fallback allowed
            count: 0
*************************** 3. row ***************************
         query id: q_4c1cf3b8080fe634
       cache name: q_4c1cf3b8080fe634
       query text: SELECT `test`.`t1`.`id`, `test`.`t1`.`name`, `test`.`t3`.`id`, `test`.`t3`.`jdoc` FROM `test`.`t1` JOIN `test`.`t3` ON (`test`.`t1`.`id` = `test`.`t
3`.`id`) WHERE (`test`.`t1`.`name` = $1)fallback behavior: fallback allowed
            count: 0
3 rows in set (0.01 sec)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.


6.测试

分别在 ReadySet 3307端口上,和后端MySQL端口上 ,执行刚才缓存的慢SQL,对比执行时间,你会发现缓存后的SQL秒级出结果。

初步测试表明,ReadySet 的有效性在第一次执行查询后,缓存机制可以充分发挥作用时就会变得非常明显。