草庐IT

Redis:内存回收的过期策略

知其然亦知其所以然 2023-03-28 原文
​有一天,产品一哥“林哥”来找我,跟我说:“小李,咱们现在一个需求,商品定时下架的逻辑,这个咱们能做到吗?”,我一想,今年的绩效跟着产品大佬走,当即拍着胸脯说道:“林哥,你就放一百个心,包在我身上~”,然后开始头脑风暴,毕竟要向前(钱)看。

案例

商品定时下架

方案一:消息队列

首先我想到当运营童鞋创建(或修改下架时间)商品后,就把该商品放到消息队列中,这样利用 RabbitMQ 的消息 TTL 加死信队列的特性,这个需求搞定,安排上线~

方案二:定时任务+消息队列

过了一段时间,架构师发哥心急火燎的来找我,我一看这阵势这是有大事吧,发哥不等我开口,说:“小李,快看看系统,运营童鞋来找我说,商品到下架时间还能买到;而且运维童鞋反应过节那天咱们的 RabbitMQ 那台服务器内存和硬盘不够用了,尽快处理下”。

我把两件事串联在一起就想到了出问题的点就是“过期自动下架”功能的问题。

第一个问题:商品到下架时间还能买到,我跟运营童鞋确认问题商品,发现很多商品的过期时间是3个月甚至更久,大致猜测可能是延迟时间过长导致了消息延迟失败,查了查默认在使用RabbitMQ的延迟消息功能时候,它的延迟极限是4294967296毫秒,也就是49.7天,很显然现有的功能是无法满足的运营需求,扑街~。

第二个问题:过节前夕 RabbitMQ 那台服务器内存和硬盘不够用,我去看运营后台发现创建了大量的新商品,那应该是大量延时下架商品放到消息队列中,以至于产生堆积。

基于以上两点,我做出以下两点改造:

  • 创建(或修改下架时间)商品的时候,不会放到消息队列中,节约资源利用空间;
  • 定时任务每天从商品表中捞取第二天下架的商品放入到消息队列中,缩短延迟时间。

搞定~

从这个案例中我借鉴的是 Redis 的内存回收策略,因为 Redis 所有的数据都是存储到内存中的,所以在某些情况下需要对占用的内存进行回收。

Redis 中同时使用了惰性过期和定期过期两种过期策略。

策略一:惰性过期

只有当访问一个 key 时,才会判断该 key 是否已过期,过期则清除。该策略可以最大化地节省 CPU 资源,却对内存非常不友好。极端情况可能出现大量的过期 key 没有再次被访问,从而不会被清除,占用大量内存。

策略二:定期过期

每隔一定的时间,会扫描一定数量的数据库的 expires 字典中一定数量的 key,并清除其中已过期的 key。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得 CPU 和内存资源达到最优的平衡效果。

END

好兄弟可以点赞并关注我的公众号“javaAnswer”,全部都是干货。

有关Redis:内存回收的过期策略的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby-on-rails - Ruby 中的内存模型 - 2

    ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

  3. 键删除后 ruby​​ 哈希内存泄漏 - 2

    你好,我无法成功如何在散列中删除key后释放内存。当我从哈希中删除键时,内存不会释放,也不会在手动调用GC.start后释放。当从Hash中删除键并且这些对象在某处泄漏时,这是预期的行为还是GC不释放内存?如何在Ruby中删除Hash中的键并在内存中取消分配它?例子:irb(main):001:0>`ps-orss=-p#{Process.pid}`.to_i=>4748irb(main):002:0>a={}=>{}irb(main):003:0>1000000.times{|i|a[i]="test#{i}"}=>1000000irb(main):004:0>`ps-orss=-p

  4. ruby-on-rails - HTTParty 的内存问题和下载大文件 - 2

    这会导致Ruby出现内存问题吗?我知道如果大小超过10KB,Open-URI会写入TempFile。但是HTTParty会在写入TempFile之前尝试将整个PDF保存到内存吗?src=Tempfile.new("file.pdf")src.binmodesrc.writeHTTParty.get("large_file.pdf").parsed_response 最佳答案 您可以使用Net::HTTP。参见thedocumentation(特别是标题为“流媒体响应机构”的部分)。这是文档中的示例:uri=URI('http://e

  5. ruby-on-rails - 覆盖 Controller 中的 protect_from_forgery 策略 - 2

    我想使用两种不同的protect_from_forgery策略构建一个Rails应用程序:一种用于Web应用程序,一种用于API。在我的应用程序Controller中,我有这行代码:protect_from_forgerywith::exception为了防止CSRF攻击,它工作得很好。在我的API命名空间中,我创建了一个继承self的应用程序Controller的api_controller,它是API命名空间中所有其他Controller的父类,我将上面的代码更改为:protect_from_forgery:null_session.遗憾的是,我在尝试发出POST请求时遇到错误:“

  6. ruby-on-rails - 内存中具有相同 ID 的更多对象? - 2

    在部署在heroku上的Rails应用程序(v:3.1)中,我在内存中获得了更多具有相同ID的对象。我的heroku控制台日志:>>Project.find_all_by_id(92).size=>2>>ActiveRecord::Base.connection.execute('select*fromprojectswhereid=92').to_a.size=>1这怎么可能?可能是什么问题? 最佳答案 解决方案根据您的SQL查询,您的数据库中显然没有重复条目。也许您的类项目中的size或length方法已被覆盖。我试过find_

  7. ruby - rails 3.0.7 内存泄漏 - 2

    我的两个不同的Rails应用程序的内存有一些奇怪的问题。这两个应用程序都使用rails3.0.7。每个Controller请求分配20-30-50MB的内存。在生产模式下,这个数量减少到5-10。但这是同样的事情。这是两个应用程序使用的gem列表:gem'pg'gem'haml'gem'sass'gem'devise'gem'simple_form'gem'state_machine'gem"globalize3","0.1.0.beta"gem"easy_globalize3_accessors"gem'paperclip'gem'andand'关闭所有这些gem不会给我任何结果。我

  8. ruby - 如何强制 Ruby 释放内存给操作系统 - 2

    正如标题,我有一个处理大量数据的ruby​​程序。该程序占用了所有内存,其中调用了系统命令hostname,并且发生错误无法分配内存-主机名我试过GC.start但它不起作用。那么如何强制ruby释放未使用的内存呢?OK,这是别人的测试代码,最后报错是big_var被回收了。但是内存仍然没有释放。require"weakref"defreportputs"#{param}:\t\tMemory"+`psax-opid,rss|grep-E"^[[:space:]]*#{$$}"`.strip.split.map(&:to_i)[1].to_s+'KB'endbig_var=""#big

  9. ruby - 如何在 Ruby 中从内存中 HTTP 发布流数据? - 2

    我想上传我在运行时用Ruby生成的数据,就像从block中提供上传数据一样。我找到的所有示例仅展示了如何流式传输必须在请求之前位于磁盘上的文件,但我不想缓冲该文件。除了滚动我自己的套接字连接之外,最好的解决方案是什么?这是一个伪代码示例:post_stream('127.0.0.1','/stream/')do|body|generate_xmldo|segment|body 最佳答案 有效的代码。require'thread'require'net/http'require'base64'require'openssl'class

  10. ruby - 执行过期异常使 Ruby 线程崩溃,但处理了 Timeout::Error - 2

    任何人都可以解释为什么当对方法的调用看起来像这样时我可能会看到这个堆栈(由HTTParty::post请求引起):beginresponse=HTTParty::post(url,options)rescuelogger.warn("Couldnotpostto#{url}")rescueTimeout::Errorlogger.warn("Couldnotpostto#{url}:timeout")end堆栈:/usr/local/lib/ruby/1.8/timeout.rb:64:in`timeout'/usr/local/lib/ruby/1.8/net/protocol.rb

随机推荐