精华内容
下载资源
问答
  • 怎么微信朋友圈缓存?各位微信用户,如果你的微信软件使用久了以后,微信就会用起来卡一点,这个是时候就要去清理微信缓存了哦,那么应该怎么微信朋友圈缓存呢?以下是方法了哦。怎么微信朋友圈缓存?如果要...

    怎么删微信朋友圈缓存?各位微信用户,如果你的微信软件使用久了以后,微信就会用起来卡一点,这个是时候就要去清理微信缓存了哦,那么应该怎么删微信朋友圈缓存呢?以下是方法了哦。

    怎么删微信朋友圈缓存?

    如果要删微信朋友圈缓存,那就直接清理微信缓存就可以了!

    有两种方法哦,具体的做法如下:

    删微信朋友圈缓存方法一:微信自带缓存清理功能

    1、首先登录微信账号,点击“我”,然后选择“设置”

    3dd2b53c546c97f76fd00c32037d8aff.png

    2、选择“通用”功能模块

    0725a8d1c5ea31f25248a8624905e33a.png

    3、选择“清理微信存储空间”功能,然后进行清理就可以了!

    a34a4f779fde2a0b039dcaf8762d0a18.png

    删微信朋友圈缓存方法二:通过第三方软件清理

    首先打开第三方软件清理,然后点击左上角“存储空间”

    88d1eea30cf0f3bfe567c1e0adf8896f.png

    进入空间管理,找到“微信专清”功能,点击“去处理”按钮

    9e85e0dcdcd451c5ef494c95d89b5fc8.png

    可清理微信的“朋友圈缓存”、“临时文件”、“聊天图片”和“聊天小视频”四大缓存垃圾文件。“朋友圈缓存”和“临时文件”支持一键清理,点击“清理”按钮即可

    6a5ab17526ac19ab25e06992d10f34de.png

    朋友圈缓存”和“临时文件”清理完毕。

    怎么删微信朋友圈缓存?以上就是怎么删微信朋友圈缓存的方法了哦,小编为大家整理出了两种删微信朋友圈缓存的方法了哦,各位微信用户都可以去试试看,希望对你有帮助,请多多的关注开淘网。

    相关阅读:查看更多相似文章

    展开全文
  • 清除服务器缓存办法

    千次阅读 2018-08-14 10:17:54
    清除服务器缓存办法 //在ashx文件中写方法 /// <summary> /// ServerMgr 的摘要说明 /// </summary> public class ServerMgr : IHttpHandler { public void ProcessRequest...
    清除服务器缓存办法
    
    //在ashx文件中写方法
    /// <summary>
        /// ServerMgr 的摘要说明
        /// </summary>
        public class ServerMgr : IHttpHandler
        {
    
            public void ProcessRequest(HttpContext context)
            {
                object returnObj = "";
                string method = context.Request["Method"];
                switch (method)
                {
                    case "clearCache": returnObj = ClearCache(context);
                PageHelper.ReturnAjaxData(context,returnObj.ToString());
                        break;
                    default:
                PageHelper.ReturnAjaxData(context,"操作失败!");
                        break;
                }
            }
    
            /// <summary>
            /// 清除服务器缓存
            /// </summary>
            public string ClearCache(HttpContext context)
            {
                IDictionaryEnumerator enumerator = HttpRuntime.Cache.GetEnumerator();
                List<string> keys = new List<string>();
                while (enumerator.MoveNext())
                {
                    keys.Add(enumerator.Key.ToString());
                }
                for (int i = 0; i < keys.Count; i++)
                {
                    HttpRuntime.Cache.Remove(keys[i]);
                }
                if (HttpRuntime.Cache.Count == 0)
                    return "刷新成功";
                else
                    return "刷新失败!";
            }
    
    
            public bool IsReusable
            {
                get
                {
                    return false;
                }
            }
        }
    }
    
    
    
    
    //js文件
    var $c = new Object();
    $c.frushCache = function () {
        if (confirm("确定清除缓存?"))
            if (window.location.host.indexOf("localhost") > -1)
                AjaxData.GetAjaxData("http://localhost:8088/Ashx/ServerMgr.ashx", { Method: 'clearCache' }, function (data) { alert(JSON.stringify(data)); }, null, null);
            else
                AjaxData.GetAjaxData("https://www.baidu.com/Ashx/ServerMgr.ashx", { Method: 'clearCache' }, function (data) { alert(JSON.stringify(data)); }, null, null);
    		
    		
    		
    //html 调用
    <a href="javascript:$c.frushCache()">刷新网站服务器缓存</a>
    		
    		
    		

     

    展开全文
  • Cache Server缓存服务器

    2019-05-01 09:33:00
    Preferences偏好设置-Cache Server缓存服务器 5、Cache Server:缓存服务器,对缓存服务器进行设置,在选中“Use Cache Server”选项后,即可在IPAddress中设置IP地址 缓存服务器 设置 属性 使用缓存服务器 选中此框...

    Preferences偏好设置-Cache Server缓存服务器

    wps15

    5、Cache Server:缓存服务器,对缓存服务器进行设置,在选中“Use Cache Server”选项后,即可在IPAddress中设置IP地址

    缓存服务器

    wps16

    设置

    属性

    使用缓存服务器

    选中此框以使用专用缓存服务器。

    IP地址

    如果启用,请在此处输入专用缓存服务器的IP地址。

    Cache Server 缓存服务器

    wps17

    Use Cache Server

    使用缓存服务器

    Should the cache server be enabled?

    启用缓存服务器吗?

    IP Address

    IP地址

    IP address of the cache server, if enabled

    如果启用,缓存服务器的IP地址。

    缓存服务器

    wps18

    设置

    属性

    使用缓存服务器

    选中此框以使用专用缓存服务器。

    IP地址

    如果启用,请在此处输入专用缓存服务器的IP地址。

    转载于:https://www.cnblogs.com/kubll/p/10799171.html

    展开全文
  • 前言当我们在做数据库与缓存数据同步时,究竟更新缓存,还是删除缓存,究竟是先操作数据库,还是先操作缓存?本文带大家深度分析数据库与缓存的双写问题,并且给出了所有方案的实现代码方便大家参考。...

    前言

    当我们在做数据库与缓存数据同步时,究竟更新缓存,还是删除缓存,究竟是先操作数据库,还是先操作缓存?本文带大家深度分析数据库与缓存的双写问题,并且给出了所有方案的实现代码方便大家参考。

    本篇文章主要内容

    • 数据缓存

      • 为何要使用缓存

      • 哪类数据适合缓存

      • 缓存的利与弊

    • 如何保证缓存和数据库一致性

      • 不更新缓存,而是删除缓存

      • 先操作缓存,还是先操作数据库

      • 非要保证数据库和缓存数据强一致该怎么办

    • 缓存和数据库一致性实战

      • 实战:先删除缓存,再更新数据库

      • 实战:先更新数据库,再删缓存

      • 实战:缓存延时双删

      • 实战:删除缓存重试机制

      • 实战:读取binlog异步删除缓存

    数据缓存

    在我们实际的业务场景中,一定有很多需要做数据缓存的场景,比如售卖商品的页面,包括了许多并发访问量很大的数据,它们可以称作是是“热点”数据,这些数据有一个特点,就是更新频率低,读取频率高,这些数据应该尽量被缓存,从而减少请求打到数据库上的机会,减轻数据库的压力。

    为何要使用缓存

    缓存是为了追求“快”而存在的。我们用代码举一个例子。

    我在自己的Demo代码仓库中增加了两个查询库存的接口getStockByDB和getStockByCache,分别表示从数据库和缓存查询某商品的库存量。

    随后我们用JMeter进行并发请求测试。(JMeter的使用请参考我之前写的文章:点击这里

    需要声明的是,我的测试并不严谨,只是作对比测试,不要作为实际服务性能的参考。

    这是两个接口的代码:

    /**
     * 查询库存:通过数据库查询库存
     * @param sid
     * @return
     */
    @RequestMapping("/getStockByDB/{sid}")
    @ResponseBody
    public String getStockByDB(@PathVariable int sid) {
        int count;
        try {
            count = stockService.getStockCountByDB(sid);
        } catch (Exception e) {
            LOGGER.error("查询库存失败:[{}]", e.getMessage());
            return "查询库存失败";
        }
        LOGGER.info("商品Id: [{}] 剩余库存为: [{}]", sid, count);
        return String.format("商品Id: %d 剩余库存为:%d", sid, count);
    }
    
    /**
     * 查询库存:通过缓存查询库存
     * 缓存命中:返回库存
     * 缓存未命中:查询数据库写入缓存并返回
     * @param sid
     * @return
     */
    @RequestMapping("/getStockByCache/{sid}")
    @ResponseBody
    public String getStockByCache(@PathVariable int sid) {
        Integer count;
        try {
            count = stockService.getStockCountByCache(sid);
            if (count == null) {
                count = stockService.getStockCountByDB(sid);
                LOGGER.info("缓存未命中,查询数据库,并写入缓存");
                stockService.setStockCountToCache(sid, count);
            }
        } catch (Exception e) {
            LOGGER.error("查询库存失败:[{}]", e.getMessage());
            return "查询库存失败";
        }
        LOGGER.info("商品Id: [{}] 剩余库存为: [{}]", sid, count);
        return String.format("商品Id: %d 剩余库存为:%d", sid, count);
    }
    

    首先设置为10000个并发请求的情况下,运行JMeter,结果首先出现了大量的报错,10000个请求中98%的请求都直接失败了。让人很慌张~

    打开日志,报错如下:

    SpringBoot内置的Tomcat最大并发数搞的鬼,其默认值为200,对于10000的并发,单机服务实在是力不从心。当然,你可以修改这里的并发数设置,但是你的小机器仍然可能会扛不住。

    将其修改为如下配置后,我的小机器才在通过缓存拿库存的情况下,保证了10000个并发的100%返回请求:

    server.tomcat.max-threads=10000
    server.tomcat.max-connections=10000
    

    可以看到,不使用缓存的情况下,吞吐量为668个请求每秒

    使用缓存的情况下,吞吐量为2177个请求每秒

    在这种“十分不严谨”的对比下,有缓存对于一台单机,性能提升了3倍多,如果在多台机器,更多并发的情况下,由于数据库有了更大的压力,缓存的性能优势应该会更加明显。

    测完了这个小实验,我看了眼我挂着MySql的小水管腾讯云服务器,生怕他被这么高流量搞挂。这种突发的流量,指不定会被检测为异常攻击流量呢~

    我用的是腾讯云服务器1C4G2M,活动买的,很便宜。这里打个免费的广告,请腾讯云看到后联系我给我打钱 ;)

    哪类数据适合缓存

    缓存量大但又不常变化的数据,比如详情,评论等。对于那些经常变化的数据,其实并不适合缓存,一方面会增加系统的复杂性(缓存的更新,缓存脏数据),另一方面也给系统带来一定的不稳定性(缓存系统的维护)。

    但一些极端情况下,你需要将一些会变动的数据进行缓存,比如想要页面显示准实时的库存数,或者其他一些特殊业务场景。这时候你需要保证缓存不能(一直)有脏数据,这就需要再深入讨论一下。

    缓存的利与弊

    我们到底该不该上缓存的,这其实也是个trade-off(权衡)的问题。

    上缓存的优点:

    • 能够缩短服务的响应时间,给用户带来更好的体验。

    • 能够增大系统的吞吐量,依然能够提升用户体验。

    • 减轻数据库的压力,防止高峰期数据库被压垮,导致整个线上服务BOOM!

    上了缓存,也会引入很多额外的问题:

    • 缓存有多种选型,是内存缓存,memcached还是redis,你是否都熟悉,如果不熟悉,无疑增加了维护的难度(本来是个纯洁的数据库系统)。

    • 缓存系统也要考虑分布式,比如redis的分布式缓存还会有很多坑,无疑增加了系统的复杂性。

    • 在特殊场景下,如果对缓存的准确性有非常高的要求,就必须考虑缓存和数据库的一致性问题

    本文想要重点讨论的,就是缓存和数据库的一致性问题,各位看官且往下看。

    如何保证缓存和数据库一致性

    说了这么多缓存的必要性,那么使用缓存是不是就是一个很简单的事情了呢,我之前也一直是这么觉得的,直到遇到了需要缓存与数据库保持强一致的场景,才知道让数据库数据和缓存数据保持一致性是一门很高深的学问。

    从远古的硬件缓存,操作系统缓存开始,缓存就是一门独特的学问。这个问题也被业界探讨了非常久,争论至今。我翻阅了很多资料,发现其实这是一个权衡的问题。值得好好讲讲。

    以下的讨论会引入几方观点,我会跟着观点来写代码验证所提到的问题。

    不更新缓存,而是删除缓存

    大部分观点认为,做缓存不应该是去更新缓存,而是应该删除缓存,然后由下个请求去去缓存,发现不存在后再读取数据库,写入缓存。

    观点引用:《分布式之数据库和缓存双写一致性方案解析》孤独烟

    原因一:线程安全角度

    同时有请求A和请求B进行更新操作,那么会出现

    (1)线程A更新了数据库

    (2)线程B更新了数据库

    (3)线程B更新了缓存

    (4)线程A更新了缓存

    这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。

    原因二:业务场景角度

    有如下两点:

    (1)如果你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。

    (2)如果你写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。显然,删除缓存更为适合。

    其实如果业务非常简单,只是去数据库拿一个值,写入缓存,那么更新缓存也是可以的。但是,淘汰缓存操作简单,并且带来的副作用只是增加了一次cache miss,建议作为通用的处理方式。

    先操作缓存,还是先操作数据库

    那么问题就来了,我们是先删除缓存,然后再更新数据库,还是先更新数据库,再删缓存呢?

    先来看看大佬们怎么说。

    《【58沈剑架构系列】缓存架构设计细节二三事》58沈剑:

    对于一个不能保证事务性的操作,一定涉及“哪个任务先做,哪个任务后做”的问题,解决这个问题的方向是:如果出现不一致,谁先做对业务的影响较小,就谁先执行。

    假设先淘汰缓存,再写数据库:第一步淘汰缓存成功,第二步写数据库失败,则只会引发一次Cache miss。

    假设先写数据库,再淘汰缓存:第一步写数据库操作成功,第二步淘汰缓存失败,则会出现DB中是新数据,Cache中是旧数据,数据不一致。

    沈剑老师说的没有问题,不过没完全考虑好并发请求时的数据脏读问题,让我们再来看看孤独烟老师《分布式之数据库和缓存双写一致性方案解析》:

    先删缓存,再更新数据库

    该方案会导致请求数据不一致

    同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么会出现如下情形:

    (1)请求A进行写操作,删除缓存

    (2)请求B查询发现缓存不存在

    (3)请求B去数据库查询得到旧值

    (4)请求B将旧值写入缓存

    (5)请求A将新值写入数据库

    上述情况就会导致不一致的情形出现。而且,如果不采用给缓存设置过期时间策略,该数据永远都是脏数据。

    所以先删缓存,再更新数据库并不是一劳永逸的解决方案,再看看先更新数据库,再删缓存这种方案怎么样?

    先更新数据库,再删缓存这种情况不存在并发问题么?

    不是的。假设这会有两个请求,一个请求A做查询操作,一个请求B做更新操作,那么会有如下情形产生

    (1)缓存刚好失效

    (2)请求A查询数据库,得一个旧值

    (3)请求B将新值写入数据库

    (4)请求B删除缓存

    (5)请求A将查到的旧值写入缓存

    ok,如果发生上述情况,确实是会发生脏数据。

    然而,发生这种情况的概率又有多少呢?

    发生上述情况有一个先天性条件,就是步骤(3)的写数据库操作比步骤(2)的读数据库操作耗时更短,才有可能使得步骤(4)先于步骤(5)。可是,大家想想,数据库的读操作的速度远快于写操作的(不然做读写分离干嘛,做读写分离的意义就是因为读操作比较快,耗资源少),因此步骤(3)耗时比步骤(2)更短,这一情形很难出现。

    先更新数据库,再删缓存依然会有问题,不过,问题出现的可能性会因为上面说的原因,变得比较低!

    所以,如果你想实现基础的缓存数据库双写一致的逻辑,那么在大多数情况下,在不想做过多设计,增加太大工作量的情况下,请先更新数据库,再删缓存!

    我非要数据库和缓存数据强一致怎么办

    那么,如果我非要保证绝对一致性怎么办,先给出结论:

    没有办法做到绝对的一致性,这是由CAP理论决定的,缓存系统适用的场景就是非强一致性的场景,所以它属于CAP中的AP。

    所以,我们得委曲求全,可以去做到BASE理论中说的最终一致性

    最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性

    大佬们给出了到达最终一致性的解决思路,主要是针对上面两种双写策略(先删缓存,再更新数据库/先更新数据库,再删缓存)导致的脏数据问题,进行相应的处理,来保证最终一致性。

    缓存延时双删

    问:先删除缓存,再更新数据库中避免脏数据?

    答案:采用延时双删策略。

    上文我们提到,在先删除缓存,再更新数据库的情况下,如果不采用给缓存设置过期时间策略,该数据永远都是脏数据。

    那么延时双删怎么解决这个问题呢?

    (1)先淘汰缓存

    (2)再写数据库(这两步和原来一样)

    (3)休眠1秒,再次淘汰缓存

    这么做,可以将1秒内所造成的缓存脏数据,再次删除。

    那么,这个1秒怎么确定的,具体该休眠多久呢?

    针对上面的情形,读者应该自行评估自己的项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上,加几百ms即可。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

    如果你用了mysql的读写分离架构怎么办?

    ok,在这种情况下,造成数据不一致的原因如下,还是两个请求,一个请求A进行更新操作,另一个请求B进行查询操作。

    (1)请求A进行写操作,删除缓存

    (2)请求A将数据写入数据库了,

    (3)请求B查询缓存发现,缓存没有值

    (4)请求B去从库查询,这时,还没有完成主从同步,因此查询到的是旧值

    (5)请求B将旧值写入缓存

    (6)数据库完成主从同步,从库变为新值

    上述情形,就是数据不一致的原因。还是使用双删延时策略。只是,睡眠时间修改为在主从同步的延时时间基础上,加几百ms。

    采用这种同步淘汰策略,吞吐量降低怎么办?

    ok,那就将第二次删除作为异步的。自己起一个线程,异步删除。这样,写的请求就不用沉睡一段时间后了,再返回。这么做,加大吞吐量。

    所以在先删除缓存,再更新数据库的情况下,可以使用延时双删的策略,来保证脏数据只会存活一段时间,就会被准确的数据覆盖。

    在先更新数据库,再删缓存的情况下,缓存出现脏数据的情况虽然可能性极小,但也会出现。我们依然可以用延时双删策略,在请求A对缓存写入了脏的旧值之后,再次删除缓存。来保证去掉脏缓存。

    删缓存失败了怎么办:重试机制

    看似问题都已经解决了,但其实,还有一个问题没有考虑到,那就是删除缓存的操作,失败了怎么办?比如延时双删的时候,第二次缓存删除失败了,那不还是没有清除脏数据吗?

    解决方案就是再加上一个重试机制,保证删除缓存成功。

    参考孤独烟老师给的方案图:

    方案一:

    流程如下所示

    (1)更新数据库数据;

    (2)缓存因为种种问题删除失败

    (3)将需要删除的key发送至消息队列

    (4)自己消费消息,获得需要删除的key

    (5)继续重试删除操作,直到成功

    然而,该方案有一个缺点,对业务线代码造成大量的侵入。于是有了方案二,在方案二中,启动一个订阅程序去订阅数据库的binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作。

    方案二:

    流程如下图所示:

    (1)更新数据库数据

    (2)数据库会将操作信息写入binlog日志当中

    (3)订阅程序提取出所需要的数据以及key

    (4)另起一段非业务代码,获得该信息

    (5)尝试删除缓存操作,发现删除失败

    (6)将这些信息发送至消息队列

    (7)重新从消息队列中获得该数据,重试操作。

    而读取binlog的中间件,可以采用阿里开源的canal

    好了,到这里我们已经把缓存双写一致性的思路彻底梳理了一遍,下面就是我对这几种思路徒手写的实战代码,方便有需要的朋友参考。

    缓存和数据库一致性实战

    实战:先删除缓存,再更新数据库

    终于到了实战,我们在秒杀项目的代码上增加接口:先删除缓存,再更新数据库

    OrderController中新增:

    /**
     * 下单接口:先删除缓存,再更新数据库
     * @param sid
     * @return
     */
    @RequestMapping("/createOrderWithCacheV1/{sid}")
    @ResponseBody
    public String createOrderWithCacheV1(@PathVariable int sid) {
        int count = 0;
        try {
            // 删除库存缓存
            stockService.delStockCountCache(sid);
            // 完成扣库存下单事务
            orderService.createPessimisticOrder(sid);
        } catch (Exception e) {
            LOGGER.error("购买失败:[{}]", e.getMessage());
            return "购买失败,库存不足";
        }
        LOGGER.info("购买成功,剩余库存为: [{}]", count);
        return String.format("购买成功,剩余库存为:%d", count);
    }
    

    stockService中新增:

    @Override
    public void delStockCountCache(int id) {
        String hashKey = CacheKey.STOCK_COUNT.getKey() + "_" + id;
        stringRedisTemplate.delete(hashKey);
        LOGGER.info("删除商品id:[{}] 缓存", id);
    }
    

    其他涉及的代码都在之前三篇文章中有介绍,并且可以直接去Github拿到项目源码,就不在这里重复贴了。

    实战:先更新数据库,再删缓存

    如果是先更新数据库,再删缓存,那么代码只是在业务顺序上颠倒了一下,这里就只贴OrderController中新增:

    /**
     * 下单接口:先更新数据库,再删缓存
     * @param sid
     * @return
     */
    @RequestMapping("/createOrderWithCacheV2/{sid}")
    @ResponseBody
    public String createOrderWithCacheV2(@PathVariable int sid) {
        int count = 0;
        try {
            // 完成扣库存下单事务
            orderService.createPessimisticOrder(sid);
            // 删除库存缓存
            stockService.delStockCountCache(sid);
        } catch (Exception e) {
            LOGGER.error("购买失败:[{}]", e.getMessage());
            return "购买失败,库存不足";
        }
        LOGGER.info("购买成功,剩余库存为: [{}]", count);
        return String.format("购买成功,剩余库存为:%d", count);
    }
    

    实战:缓存延时双删

    如何做延时双删呢,最好的方法是开设一个线程池,在线程中删除key,而不是使用Thread.sleep进行等待,这样会阻塞用户的请求。

    更新前先删除缓存,然后更新数据,再延时删除缓存。

    OrderController中新增接口:

    
    // 延时时间:预估读数据库数据业务逻辑的耗时,用来做缓存再删除
    private static final int DELAY_MILLSECONDS = 1000;
    
    
    /**
     * 下单接口:先删除缓存,再更新数据库,缓存延时双删
     * @param sid
     * @return
     */
    @RequestMapping("/createOrderWithCacheV3/{sid}")
    @ResponseBody
    public String createOrderWithCacheV3(@PathVariable int sid) {
        int count;
        try {
            // 删除库存缓存
            stockService.delStockCountCache(sid);
            // 完成扣库存下单事务
            count = orderService.createPessimisticOrder(sid);
            // 延时指定时间后再次删除缓存
            cachedThreadPool.execute(new delCacheByThread(sid));
        } catch (Exception e) {
            LOGGER.error("购买失败:[{}]", e.getMessage());
            return "购买失败,库存不足";
        }
        LOGGER.info("购买成功,剩余库存为: [{}]", count);
        return String.format("购买成功,剩余库存为:%d", count);
    }
    

    OrderController中新增线程池:

    // 延时双删线程池
    private static ExecutorService cachedThreadPool = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
    
    
    /**
     * 缓存再删除线程
     */
    private class delCacheByThread implements Runnable {
        private int sid;
        public delCacheByThread(int sid) {
            this.sid = sid;
        }
        public void run() {
            try {
                LOGGER.info("异步执行缓存再删除,商品id:[{}], 首先休眠:[{}] 毫秒", sid, DELAY_MILLSECONDS);
                Thread.sleep(DELAY_MILLSECONDS);
                stockService.delStockCountCache(sid);
                LOGGER.info("再次删除商品id:[{}] 缓存", sid);
            } catch (Exception e) {
                LOGGER.error("delCacheByThread执行出错", e);
            }
        }
    }
    

    来试验一下,请求接口createOrderWithCacheV3:

    日志中,做到了两次删除:

    实战:删除缓存重试机制

    上文提到了,要解决删除失败的问题,需要用到消息队列,进行删除操作的重试。这里我们为了达到效果,接入了RabbitMq,并且需要在接口中写发送消息,并且需要消费者常驻来消费消息。Spring整合RabbitMq还是比较简单的,我把简单的整合代码也贴出来。

    pom.xml新增RabbitMq的依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    

    写一个RabbitMqConfig:

    @Configuration
    public class RabbitMqConfig {
    
        @Bean
        public Queue delCacheQueue() {
            return new Queue("delCache");
        }
    
    }
    

    添加一个消费者:

    @Component
    @RabbitListener(queues = "delCache")
    public class DelCacheReceiver {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(DelCacheReceiver.class);
    
        @Autowired
        private StockService stockService;
    
        @RabbitHandler
        public void process(String message) {
            LOGGER.info("DelCacheReceiver收到消息: " + message);
            LOGGER.info("DelCacheReceiver开始删除缓存: " + message);
            stockService.delStockCountCache(Integer.parseInt(message));
        }
    }
    

    OrderController中新增接口:

    /**
     * 下单接口:先更新数据库,再删缓存,删除缓存重试机制
     * @param sid
     * @return
     */
    @RequestMapping("/createOrderWithCacheV4/{sid}")
    @ResponseBody
    public String createOrderWithCacheV4(@PathVariable int sid) {
        int count;
        try {
            // 完成扣库存下单事务
            count = orderService.createPessimisticOrder(sid);
            // 删除库存缓存
            stockService.delStockCountCache(sid);
            // 延时指定时间后再次删除缓存
            // cachedThreadPool.execute(new delCacheByThread(sid));
            // 假设上述再次删除缓存没成功,通知消息队列进行删除缓存
            sendDelCache(String.valueOf(sid));
    
        } catch (Exception e) {
            LOGGER.error("购买失败:[{}]", e.getMessage());
            return "购买失败,库存不足";
        }
        LOGGER.info("购买成功,剩余库存为: [{}]", count);
        return String.format("购买成功,剩余库存为:%d", count);
    }
    

    访问createOrderWithCacheV4:

    可以看到,我们先完成了下单,然后删除了缓存,并且假设延迟删除缓存失败了,发送给消息队列重试的消息,消息队列收到消息后再去删除缓存。

    实战:读取binlog异步删除缓存

    我们需要用到阿里开源的canal来读取binlog进行缓存的异步删除。

    我写了一篇Canal的入门文章,其中用的入门例子就是读取binlog删除缓存。大家可以直接跳转到这里:阿里开源MySQL中间件Canal快速入门

    扩展阅读

    更新缓存的的Design Pattern有四种:

    • Cache aside

    • Read through

    • Write through

    • Write behind caching,这里有陈皓的总结文章可以进行学习。

    https://coolshell.cn/articles/17416.html

    小结

    引用陈浩《缓存更新的套路》最后的总结语作为小结:

    分布式系统里要么通过2PC或是Paxos协议保证一致性,要么就是拼命的降低并发时脏数据的概率

    缓存系统适用的场景就是非强一致性的场景,所以它属于CAP中的AP,BASE理论。

    异构数据库本来就没办法强一致,只是尽可能减少时间窗口,达到最终一致性

    还有别忘了设置过期时间,这是个兜底方案

    结束语

    本文总结并探讨了缓存数据库双写一致性问题。

    文章内容大致可以总结为如下几点:

    • 对于读多写少的数据,请使用缓存。

    • 为了保持数据库和缓存的一致性,会导致系统吞吐量的下降。

    • 为了保持数据库和缓存的一致性,会导致业务代码逻辑复杂。

    • 缓存做不到绝对一致性,但可以做到最终一致性。

    • 对于需要保证缓存数据库数据一致的情况,请尽量考虑对一致性到底有多高要求,选定合适的方案,避免过度设计。

    作者水平有限,写文章过程中难免出现错误和疏漏,请理性讨论与指正。

    参考

    • https://cloud.tencent.com/developer/article/1574827

    • https://www.jianshu.com/p/2936a5c65e6b

    • https://www.cnblogs.com/rjzheng/p/9041659.html

    • https://www.cnblogs.com/codeon/p/8287563.html

    • https://www.jianshu.com/p/0275ecca2438

    • https://www.jianshu.com/p/dc1e5091a0d8

    • https://coolshell.cn/articles/17416.html

    如果文章对你有帮助,不妨点赞,收藏起来~

    
    往期推荐
    

    磊哥工作十几年了,竟没有用过do-while!(文末送书)

    2020-09-06

    3种时间格式化的方法,SpringBoot篇!

    2020-09-04

    多图证明,Java到底是值传递还是引用传递?

    2020-09-02

    阿里为什么推荐使用LongAdder,而不是volatile?

    2020-08-25

    关注下方二维码,收获更多干货!

    展开全文
  • Jboss 服务器缓存jsp问题

    千次阅读 2014-09-04 15:59:01
    JBoss站点在Deploy后服务器会对这些jsp文件进行动态编译,因此除非重启服务器(注意是机器,不是Sevice),否则这些缓存可能会一直存在,之所以说可能, 是因为服务器会不定时进行清理, 但这个时间可能是几小时, 也可能是几...
  • 清除nginx服务器网站缓存数据

    万次阅读 2018-04-16 11:47:53
    公司网站上线之后后面老是出现一些小的bug,但是这些bug在vi上改了之后打开更改的网页却发现并没有更改,google了一下有些人说删除“/var/cache/nginx”文件夹,但是我找到了这个文件夹了之后重启nginx还是没什么...
  • 环境:阿里云服务器,Redis4.0 目标:清理redis缓存 1、进入到你的redis安装路径中(我的就在根目录下) 2、按照图输入命令 3、输入 keys *(匹配所有values) 4、输入flushall ...
  • Redis缓存服务器 本文转自 https://blog.51cto.com/13447608/2159501 redis 的简单介绍 Redis是一个开源(BSD许可)的,ANSI C语言编写的,高级键值(key-value)缓存和支持永久存储NoSql数据库产品。内存中的数据...
  • 尊天缓存功能上 支持键 值对的增 改 查全部操作 尊天缓存与memcache radis的比较:尊天缓存独有的高并发技术 天生适应高并发高吞吐的服务器环境 性能提升10倍以上 尊天缓存应对大数据量的方法就是使用64位版本 ...
  • 缓存服务器设计与实现(六)

    千次阅读 2016-01-05 15:40:07
    本文讲缓存中的内容管理--文件的删除。
  • 缓存服务器---redis与memcached的对比

    千次阅读 2018-04-12 17:53:33
    memcached与redis实现的对比非常好的一篇文章,忍不住要转载: 腾云阁 https://www.qcloud.com/communitymemcached和redis,作为近些年最常用的缓存服务器,相信大家对它们再熟悉不过了。前两年还在学校时,我曾经...
  • 缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例。 这样做可以减少系统开销... 二、内存缓存,也就是实现一个类中静态Map,对这个Map进行常规的增查. 接下
  • 缓存

    2018-07-18 16:53:01
    缓存 利用项目闲暇时间,对缓存知识进行了一次梳理,整理成了脑图,这里配合脑图进行一下说明。 脑图:缓存知识点整理 [TOC] 缓存简介 缓存的本质是让数据更接近使用者,如何设计缓存、哪些数据适合进行缓存...
  • 缓存服务器设计与实现(四)

    千次阅读 2013-02-19 17:41:16
    这里我们聚焦一个问题,就是缓存满的情况。一般的cache都会配置容量,无论是内存缓存还是磁盘缓存,都不能无节制的去使用他们。这里以磁盘缓存为例,如果配置的限额已用完,该如何处理呢?  对于nginx,...
  • memcached缓存使用演示

    2019-01-09 19:11:32
    memcached缓存使用演示小项目,缓存服务器的搭建,增改查缓存
  • (如果数据库中数据删除失败,也不会有业务逻辑上的影响)修改数据:先删缓存中数据,再修改数据库中数据,再添加至缓存。(无论是修改数据库失败,还是添加至缓存失败,都对业务逻辑无影响)(注意:这里是删除缓存...
  • 缓存Memcached以及缓存策略

    万次阅读 2014-05-14 09:56:17
    缓存是我们在设计中考虑的如何提高软件性能的方法,使用memcached这款简单的K/V缓存,提升软件性能,降低服务器压力。
  • http缓存

    千次阅读 2021-03-30 21:55:47
    目录前言强制缓存ExpiresCache-Control协商缓存Last-Modified与If-Modified-SinceEtag与If-None-Match缓存的优点不同刷新的请求执行过程总结...  在浏览器第一次发起请求时,本地无缓存,向web服务器发送请求,服务
  • 在ASP.NET MVC中,假如我们想要将某个页面(即某个Action)缓存服务器端,可以在Action上标上以下特性:
  • 1.缓存穿透 1.1 什么是缓存穿透? 1.2 缓存穿透的解决方案 2.缓存击穿 2.1 什么是缓存击穿? 2.2 缓存击穿的解决方啊 3.缓存雪崩 3.1 什么是缓存雪崩? 3.2 缓存雪崩的解决方案 4.分布式锁 4.1 使用setnx ...
  • 排查问题发现,原来是B系统的Redis key序列化方式与A系统不一致,导致缓存删除失败。
  • ehcache缓存技术讲解

    千次阅读 2017-11-10 21:22:27
    缓存实际上是为了减轻数据库服务器的负载,使用缓存,我们可以将一些常用的数据放入缓存,因为这些数据经常性的使用,大大增加了服务器的负载,但是当放入缓存后,在使用这些数据的时候,首先会从缓存中查找,如果...
  • 在前文我们介绍了如何使用Redis或者Caffeine来做缓存。 Spring Boot缓存实战 Redis 设置有效时间和自动刷新缓存-2 Spring Boot缓存实战 Caffeine 问题描述: 通过使用redis和Caffeine来做缓存,我们会发现一些...
  • mycati缓存cache

    千次阅读 2017-06-17 18:32:25
    缓存  缓存是系统常用的,其特点是保存数据到内存中。目前流行的缓存服务有MongoDB,Redis,Ehcache等。缓存是在计算机内存上保存的数据,在读取的时候无需从磁盘读入,因此具备快速读取和使用的特点,如果缓存命中...
  • 缓存:将相同查询条件的sql语句执行一遍后所得到的结果存在内存或者某种缓存介质当中,当下次遇到一模一样的查询sql时候不在执行sql与数据库交互,而是直接从缓存中获取结果,减少服务器的压力; myb...
  • 浏览器HTTP缓存机制

    2017-10-10 20:37:36
    当客户端再次请求时,可以直接从本地缓存中读取,这样减少了http请求和服务器负担,加快客户端加载网页速度,提高用户体验,那么这个就是客户端缓存的意义了。  Http 缓存机制作为 web 性能优化的重要手段,很多...
  • EAS 清缓存

    2019-02-28 17:41:37
    服务器清除缓存:$EAS_HOME\apusic\domains\server(n)\deploy目录,删除deploy目录下的apusic缓存文件,重启应用服务器即可;删除前请先做好备份,避免误删和错 服务器端磁盘扩容: 管理控制台日志:$EAS_H....
  • 看完这篇,让你吃透 Redis 的缓存穿透、缓存击穿、缓存雪崩问题缓存的基本使用缓存穿透问题描述解决方案1. 异常参数校验2. 空值缓存3. 布隆过滤器缓存击穿问题描述解决方案1. 设置热点数据永远不过期2. 设置热点数据...
  • 使用Go语言实现的分布式缓存,纯go语言项目,并非对已有的分布式缓存数据库的封装,内部使用map存储数据,并且实现了持久化与动态增删服务器节点的功能。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 62,577
精华内容 25,030
关键字:

如何删服务器缓存