在项目中难免会使用到redis作为缓存,去减轻数据库的访问压力,但是涉及到数据更新时,如果redis和数据库的操作设计出现问题,就会导致redis缓存中和数据库中的数据不一致的情况。那么我们如何去保证缓存与数据库中数据一致呢?
想要保证缓存与数据库的双写一致,一共有四种方式,即四种同步策略
1、先更新缓存,再更新数据库
2、先更新数据库,再更新缓存
3、先删除缓存,在更新数据库
4、先更新数据库,再删除缓存
更新缓存和删除缓存的选择
更新缓存
优点:
如果每次数据变化都能被及时更新,那么查询数据时不容易出现不命中的情况,
缺点:
1、如果数据的计算复杂,频繁的更新会造成服务器性能的消耗比较大
2、如果数据并不是被频繁使用,那么频繁更新也只是浪费服务器性能,对业务没有多大的帮助
适用于数据使用较为频繁,且数据的计算不那么复杂的场景
删除缓存
优点:不需要顾忌数据的复杂性,直接删除即可
缺点:查询数据时,增大未命中的几率,从而增大数据库的访问压力
适用于数据使用频率不高的场景
在上面四种同步策略中,都存在导致数据不一致的风险

操作步骤:
a、线程A删除缓存中的数据,
b、线程A更新数据库中的数据,但是更新失败
c、此时线程B去获取缓存中的数据,但是未命中
d、线程B,去数据库中获取数据,但此时的数据因为更新失败为旧数据
e、线程B将数据库中查到的数据同步到缓存中去
f、线程A此时更新数据到数据库成功
最后数据库和redis缓存中的数据不一致
如果在更新数据库时没有出现失败,也同样存在会造成数据不一致的情况

操作步骤:
a、线程A删除缓存中的数据,
b、此时线程B去获取缓存中的数据,但是未命中
c、线程B,去数据库中获取数据,但此时的数据因为更新失败为旧数据
d、线程B将数据库中查到的数据同步到缓存中去
e、线程A此时更新数据到数据库成功
最后数据库和redis缓存中的数据不一致,这里造成的数据不一致的原因是线程B在数据库还未更新时就已经获取到了旧的数据。

操作步骤:
1、线程A更新数据库中的数据
2、线程A删除缓存中的数据,删除失败
3、线程B查询缓存中的数据,查询到旧数据
4、线程A异步重试删除缓存
这里,删除缓存中数据失败后就会造成线程B获取到缓存中的旧数据,从而导致数据不一致的情况
如果缓存没有删除失败的情况也可能导致数据不一致

操作步骤:
1、线程A更新数据库中的数据
2、线程B查询缓存中的数据,查询到旧数据
3、线程A删除缓存
如果线程B在缓存删除前获取到了缓存中的数据,那么线程B获取到的还是旧数据,也会导致数据不一致的情况
上面中先删除缓存,在更新数据库在不出现失败时也会出现数据不一致的情况,那么我们要有什么解决方案呢。我们就采用延时双删的策略来保证缓存中的数据时更新后的数据
操作步骤
1、先删除缓存
2、更新数据库
3、线程等待 N秒(等待时间根据具体业务来判断)
4、再删除缓存
这样就保证了缓存中的数据最终会和数据库中的数据保持一致
1、更新数据库
2、生成binlog增量消费日志,
3、推送binlog日志到消息队列中
4、根据binlog日志对redis进行数据更新
数据读取:从redis中读取热点数据
数据更新:将数据更新到数据库中
数据同步:根据binlog日志,将数据同步到redis中
增量:对数据的增删改。
当数据发生增删改的操作时,先将数据在数据库中进行增量操作,并把binlog日志推送给消息中间件,订阅过的redis或者会接收到对于的binlog消息,redis根据binlog日志的内容对数据进行增量操作,这类似mysql的主从备份,利用binlog日志达到数据一致性的目的
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为