zdppy+vue3+onlyoffice文档管理系统实战 20240825上课笔记 zdppy_cache框架增加resize清理缓存的方法

news2024/11/14 3:48:24

遗留问题

  • 设置缓存,已完成
  • 获取缓存,已实现
  • 删除缓存,已实现
  • 查询所有key,带查询参数:active只查激活的,value包含value默认只获取key
  • 查询缓存大小
  • 清空缓存
  • 判断是否为管理员

实现删除缓存的接口

async def delete(req):
    """删除缓存的接口"""
    data = await api.req.get_json(req)
    key = data.get("key")
    admin_cache.delete(key)
    return api.resp.success()

测试:

req -X DELETE -d '{\"key\":1}' http://127.0.0.1:8888/zdppy_cache

查询缓存接口

基本设计

批量查询缓存信息:
```bash
# 默认查询所有的key,
req  http://127.0.0.1:8888/zdppy_caches

# 只查询未过期的keys
req -d '{\"active\":true}' http://127.0.0.1:8888/zdppy_caches

# 查看key-value格式
req -d '{\"active\":true, \"value\":true}' http://127.0.0.1:8888/zdppy_caches

# 查询详细缓存信息
req -d '{\"active\":true, \"value\":true, \"detail\":true}' http://127.0.0.1:8888/zdppy_caches

先实现默认查询所有的key

async def query(req):
    """查询缓存的接口"""
    params = await api.req.get_json(req)
    if params.get("error"):
        params = None

    data = admin_cache.get_all_keys()
    return api.resp.success({
        "query": params,
        "data": data,
    })

只查询未过期的

async def query(req):
    """查询缓存的接口"""
    params = await api.req.get_json(req)
    data = []
    if params.get("error"):
        params = None
        # 查询所有的key
        data = admin_cache.get_all_keys()
    elif params.get("active"):
        # 只查询未过期的
        data = admin_cache.get_all_keys(True)
    return api.resp.success({
        "query": params,
        "data": data,
    })

设置缓存:

req -X POST -d '{\"key\":1,\"value\":111, \"expire\": 1}' http://127.0.0.1:8888/zdppy_cache
req -X POST -d '{\"key\":2,\"value\":222, \"expire\": 2}' http://127.0.0.1:8888/zdppy_cache
req -X POST -d '{\"key\":3,\"value\":333, \"expire\": 333}' http://127.0.0.1:8888/zdppy_cache

先查询所有的key:

req http://127.0.0.1:8888/zdppy_caches

只查询未过期的key:

req -d '{\"active\":true}' http://127.0.0.1:8888/zdppy_caches

自动清理缓存的逻辑

底层核心代码

def _cull(self, now, sql, cleanup, limit=None):
    """
    这个方法是用来清空过期缓存的,无论是否超过限制
    :param now: 当前时间的秒值,浮点数
    :param sql: 执行清除的SQL语句
    :param cleanup: 要清除的文件夹(缓存对象)
    :param limit: 限制多少
    """
    cull_limit = self.cull_limit if limit is None else limit
    if cull_limit == 0:
        return

    # 查询已经过期的key
    select_expired_template = (
        'SELECT %s FROM Cache'
        ' WHERE expire_time IS NOT NULL AND expire_time < ?'
        ' ORDER BY expire_time LIMIT ?'
    )
    select_expired = select_expired_template % 'filename'
    rows = sql(select_expired, (now, cull_limit)).fetchall()

    if rows:
        # 如果查询到了就删除
        delete_expired = 'DELETE FROM Cache WHERE rowid IN (%s)' % (
                select_expired_template % 'rowid'
        )
        sql(delete_expired, (now, cull_limit))

        for (filename,) in rows:
            cleanup(filename)

        cull_limit -= len(rows)

        if cull_limit == 0:
            return

    # Evict keys by policy.

    select_policy = EVICTION_POLICY[self.eviction_policy]['cull']

    if select_policy is None or self.volume() < self.size_limit:
        return

    select_filename = select_policy.format(fields='filename', now=now)
    rows = sql(select_filename, (cull_limit,)).fetchall()

    if rows:
        delete = 'DELETE FROM Cache WHERE rowid IN (%s)' % (
            select_policy.format(fields='rowid', now=now)
        )
        sql(delete, (cull_limit,))

        for (filename,) in rows:
            cleanup(filename)

现在的问题

我们每次set的时候,它都会触发,默认会删除最早过期的十个缓存。

这样不太合理?

因为我只有三个缓存,但是因为过期时间可能比较短,会导致每次set的时候,另一个都可能被删除,这样的库里面找不到全量的记录。

这个方法默认只删除十条,少的时候删除了不爽。多的时候,比如一下子几百个过期,只删除10条好像也没啥用?

你拿过期的缓存来干啥?

  • 1、开发运维的时候可以查询
  • 2、可以感知到别人的攻击,留底别人的记录,比如一下子多了很多失效的验证码,这属于异常数据,可以被分析出来

什么时候清除合适?

  • 1、定时任务,但是这个成本比较高,因为有个定时任务必须随时跑着,可能需要消耗不少系统资源
  • 2、通过物理上限,也就是size_limit这个参数去控制,这个是比较合理的

size_limit 到底有没有生效?

通过全局密码搜索,我们可以发现,只有_cull这个方法用到了size_limit这个参数。
在这里插入图片描述

这段代码是:

# 根据policy执行删除
# least-recently-stored
select_policy = EVICTION_POLICY[self.eviction_policy]['cull']
# 默认是:SELECT {fields} FROM Cache ORDER BY store_time LIMIT ?
if select_policy is None or self.volume() < self.size_limit:
    return
select_filename = select_policy.format(fields='filename', now=now)
rows = sql(select_filename, (cull_limit,)).fetchall()
if rows:
    delete = 'DELETE FROM Cache WHERE rowid IN (%s)' % (
        select_policy.format(fields='rowid', now=now)
    )
    sql(delete, (cull_limit,))

    for (filename,) in rows:
        cleanup(filename)

这里的代码从理论上来说是没啥问题的,但是确实不太符合如下需求:

  • 1、开发运维的时候可以查询已过期的缓存
  • 2、可以感知到别人的攻击,留底别人的记录,比如一下子多了很多失效的验证码,这属于异常数据,可以被分析出来

得出结论:这个方法应该被优化。

怎么优化?

  • 1、set的时候执行的清空缓存的逻辑,没有必要特别的复杂,我们只希望,如果超过了size_limit,则清空缓存。
  • 2、到底清空多少呢?
    • 1、最早过期的10,100,1000条
    • 2、所有已过期的缓存
  • 3、想法:除了最近过期的1000条缓存,其他的都删除!!!

SQL怎么实现清空逻辑

想法:除了最近过期的1000条缓存,其他的都删除!!!

最近的1000条数据的ID。

select id from cache order by add_time desc limit 1000

删除不是这些ID的:ids

delete from cache where id not in ids

核心代码:

DELETE FROM your_table_name WHERE id NOT IN (1, 3, 5);

如果封装成子查询就是:

DELETE FROM your_table_name WHERE id NOT IN (select id from cache order by add_time desc limit 1000);

封装方法

def resize(self):
    """
    根据size_limit缓存上限清理缓存
    会删除除了最近1000条已过期的缓存以外的其他所有缓存
    """
    child_sql = "SELECT rowid FROM Cache ORDER BY expire_time DESC LIMIT 1000"
    delete_sql = f'DELETE FROM Cache WHERE rowid NOT IN {child_sql}'
    self._sql(delete_sql)

测试:sizelimit设置的小一点,比如100。插入2000条1秒过期的数据,查询所有的keys个数。调用resize方法,再查询所有的keys的个数。

from zdppy_cache import Cache

# 实例化缓存对象,指定缓存目录
cache = Cache('tmp')
for i in range(2000):
    cache.set(f"k{i}", i, 1)
print(len(cache.get_all_keys()))

cache.resize(1111)
print("resize之后", len(cache.get_all_keys()))

# 关闭缓存对象
cache.close()

清除总结

  • 1、delete_all:物理删除,整个文件夹删除
  • 2、delte:删除key对应的
  • 3、resize:只保留最近limit条删除

需求

  • 1、将resize封装为api接口
  • 2、查询所有key,带查询参数:active只查激活的,value包含value默认只获取key
  • 3、查询缓存大小
  • 4、清空缓存
  • 5、判断是否为管理员

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2074330.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[C语言]一、C语言基础

G:\Cpp\C语言精讲 1. C语言入门 1.1 初识计算机语言 计算机编程语言&#xff0c;就是人与计算机交流的方式。人们可以使用编程语言对计算机下达命令&#xff0c;让计算机完成人们需要的功能。 计算机语言有很多种。如&#xff1a;C 、C、Java、Go、JavaScript、Python&#x…

音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息

通过FFprobe命令可以显示WAV音频文件每个packet&#xff08;也称为数据包或多媒体包&#xff09;的信息&#xff1a; ffprobe -of json -show_packets XXX.wav 输出如下&#xff1a; 其中&#xff1a; 1.codec_type&#xff1a;packet类型&#xff0c;表示该路流是视频还是音…

【CSS】使用 CSS 自定义属性(变量)-- var()

自定义属性&#xff08;有时候也被称作CSS 变量或者级联变量&#xff09;是由 CSS 作者定义的&#xff0c;它包含的值可以在整个文档中重复使用。由自定义属性标记设定值&#xff08;比如&#xff1a; --main-color: black;&#xff09;&#xff0c;由 var() 函数来获取值&…

一台电脑配置两个Git账号(github和gitlab),不同仓库使用不同的git

我们工作时一般都是使用gitlab&#xff0c;工作电脑也一般配置的 git 是连接 gitlab 的&#xff0c;那么当我们如果想用同一个电脑实现不同仓库根据自己的需要到底是推送代码到github还是 gitlab&#xff0c;以及使用哪个账号&#xff0c;(比如如果想用工作电脑维护自己的 gith…

C语言学习,Turbo C 开发环境回顾

&#xff08;1&#xff09;Turbo C 集成开发环境&#xff1a; &#xff08;2&#xff09;按AltF&#xff0c;进入File菜单&#xff1a; &#xff08;3&#xff09;按AltR&#xff0c;进入Run菜单&#xff1a; &#xff08;4&#xff09;按AltC&#xff0c;进入Compile菜单&…

Java 入门指南:Java 泛型(generics)

Java 泛型概要 Java 泛型&#xff08;generics&#xff09; 是 JDK 5 中引入的一个新特性。泛型的本质是参数化类型&#xff0c;也就是所操作的数据类型被指定为一个参数&#xff08;可以称之为类型形参&#xff0c;然后在使用/调用时传入具体的类型。&#xff09; 使用 Java …

【机器学习】特征工程的基本概念以及LASSO回归和主成分分析优化方法

引言 特征工程是机器学习中的一个关键步骤&#xff0c;它涉及到从原始数据中提取和构造新的特征&#xff0c;以提高模型的性能和预测能力LASSO&#xff08;Least Absolute Shrinkage and Selection Operator&#xff09;回归是一种用于回归分析的线性模型&#xff0c;它通过引入…

字节跳动-生活服务-java后端-一面

基础题 计算机网络 1.tcp三次握手和四次挥手&#xff1f;tcp的第三次握手可以传输应用层数据嘛&#xff1f; 4.1 TCP 三次握手与四次挥手面试题 | 小林coding (xiaolincoding.com) 2.描述一下打开百度首页后发生的网络过程&#xff1f; 计算机网络面试题 | 小林coding (xi…

linux-基础知识1

简单命令 init 0 关机 int 6 重启 pwd 查看当前所在目录&#xff0c; cd切换目录 ls 列出目录下的内容 clear 清屏 date 查看时间 路径 linux表示硬件设备的文件在dev目录 /tmp是临时目录&#xff0c;可以创建目录和文件&#xff0c;但不能保证安全 df查看文件系统…

数据仓库系列 1:什么是数据仓库,它与传统数据库有什么不同?

想象一下,你正站在一座巨大的仓库前。这座仓库不是用来存放普通商品的,而是存储着海量的数据 - 这就是数据仓库。在大数据时代,数据仓库已经成为企业数据管理的核心。但它究竟是什么?又为什么如此重要?让我们一起揭开数据仓库的神秘面纱,探索它与我们熟知的传统数据库有何不同…

IDEA2023的激活与安装

前言 开始了java的学习之旅&#xff0c;当然少不了IDEA这个得力的开发工具软件。但是IDEA是付费的&#xff0c;免费版功能有太少&#xff0c;怎么使用上正式版呢&#xff01;当然还是激活啦 第一步&#xff1a;官网下载安装包 安装步骤就不展现了&#xff0c;无脑下一步就可以…

【学习笔记】技术分析-华为智驾控制器MDC Pro 610分析

华为的智能驾驶控制器一直在迭代&#xff0c;和网络上广泛披露的早期MDC 610相比&#xff0c;华为 MDC Pro 610 智能驾驶控制器&#xff0c;现在的样品设计采用了海思的双系统级芯片 (SoC) 提高了处理能力&#xff0c;三星的存储模块为无缝数据处理提供了充足的内存&#xff0c…

高并发业务下的无损技术方案设计

0 前言 秒杀&#xff0c;既有需求真实且迫切的用户&#xff0c;也有试图牟利的黄牛。系统挑战&#xff0c;就是相较于以往千倍万倍的用户规模&#xff0c;可能是真人可能是机器人&#xff0c;在同一瞬间对系统发起冲击&#xff0c;需要海量的计算资源才能支撑。 秒杀系统的设计…

Long Short-Term Memory

这篇论文总结的太抽象了&#xff0c;只是翻译了一遍。 &#xff08;我太笨了&#xff0c;如果把这个当我的入门读物&#xff0c;我觉着会把我折磨坏&#xff09; 递归神经网络的一个重要优点是它们在映射输入和输出序列时使用上下文信息的能力。不幸的是&#xff0c;对于标准的…

51单片机——按键控制

1、按键介绍 轻触按键&#xff1a;相当于是一种电子开关&#xff0c;按下时开关接通&#xff0c;松开时开关断开&#xff0c;实现原理是通过轻触按键内部的金属弹片受力弹动来实现接通和断开。 2、按键的抖动 对于机械开关&#xff0c;当机械触点断开、闭合时&#xff0c;由于…

基于SpringBoot+Vue的家教管理系统

文章目录 前言1.项目类型2.技术栈介绍1.客户端技术栈介绍2.服务端技术栈介绍 3.功能介绍1.客户端功能2.服务单功能 4.项目亮点5.适用场景6.项目展示1.客户端展示2.服务端展示 7.诚邀参与 前言 大家好&#xff0c;我是执手天涯&#xff0c;今天非常荣幸地向大家介绍一款基于Spr…

关于ssrf的实现

ssrf漏洞形成 SSRF(Server-Side Request Forgery:服务器端请求伪造)漏洞形成的原因主要是服务器端所提供的接口中包含了所要请求的内容的URL参数&#xff0c;并且未对客户端所传输过来的URL参数进行过滤 ssrf实现 本次ssrf于Pikachu靶场上实现 我们可以先拉取镜像 docker …

计算机毕业设计Spark+Tensorflow股票推荐系统 股票预测系统 股票可视化 股票数据分析 量化交易系统 股票爬虫 股票K线图 大数据毕业设计 AI

1. 需求分析 基于Spark的股票大数据分析及可视化系统是一个利用Spark分布式计算框架进行股票市场数据处理、分析和可视化的系统。它能够处理大规模的实时股票数据&#xff0c;包括股票价格、交易量、市场指标等&#xff0c;提供实时数据处理、数据可视化与展示和并提供相应决策…

【图像增强】使用 Albumentations Python 库(02)

一、说明 在本博客的第 1 部分中&#xff0c;我介绍了使用 Albumentations Python 库进行图像增广的基础知识。本部分介绍高级详细信息。 二、使用 Albumentations 进行语义分割任务 我们将使用来自 TGS 盐鉴定挑战赛的图像和数据。TGS Salt Identification Challenge | Kaggl…

基于carsim的线控转向仿真(2)--齿条力观测

观测器更详细的介绍文章可以关注博主以下两篇文章 从小车倒立摆系统看系统建模控制LQRLQE仿真_lqr平衡小车仿真模型-CSDN博客 好玩的直流电机调速实验、PID、极点配置、LQR、观测器&#xff1b;不讲大道理_观测器极点配置-CSDN博客 三个实例迅速掌握经典卡尔曼滤波用法_卡尔…