搜尋
首頁後端開發php教程程式設計技術快取寫法(三)

上次我們說了多層緩存,本章詳細介紹下記憶體緩存該如何設計。

一:分析設計

假設有個項目有一定並發量,要用到多級緩存,如下:

程式設計技術快取寫法(三)

在實際設計一個內存緩存前,我們需要考慮的問題:

1:內存與Redis的資料置換,盡可能在記憶體中提高資料命中率,減少下一級的壓力。

2:記憶體容量的限制,需要控制快取數量。

3:熱點資料更新不同,需要可設定單一key過期時間。

4:良好的快取過期刪除策略。

5:快取資料結構的複雜度盡可能的低。

關於置換及命中率:我們採用LRU演算法,因為它實作簡單,快取key命中率也很好。

LRU即是:把最近最少存取的資料給淘汰掉,經常被存取到即是熱點資料。

關於LRU資料結構:因為key優先權提升和key淘汰,所以需要順序結構。我看到大多實現,都採用鍊錶結構、

即:新資料插入到鍊錶頭部、被命中時的資料移動到頭部。 加入複雜度O(1) 移動和取得複雜度O(N)。

有沒複雜度更低的呢? 有Dictionary,複雜度為O(1),效能最好。 那如何保證快取的優先權提升呢?

二:O(1)LRU實作

我們定義個LRUCache類,建構參數maxKeySize 來控制快取最大數量。

使用ConcurrentDictionary來作為我們的快取容器,並且可以確保線程安全。

public class LRUCache<TValue> : IEnumerable<KeyValuePair<string, TValue>>
   {
       private long ageToDiscard = 0;  //淘汰的年龄起点
       private long currentAge = 0;        //当前缓存最新年龄
       private int maxSize = 0;          //缓存最大容量
       private readonly ConcurrentDictionary<string, TrackValue> cache;
       public LRUCache(int maxKeySize)
       {
           cache = new ConcurrentDictionary<string, TrackValue>();
           maxSize = maxKeySize;
       }
   }

上面定義了 ageToDiscard、currentAge 這2個自加值參數,作用是:標記快取清單中各個key的新舊程度。

核心實作步驟如下:

1:每次加入key時,currentAge自增並將currentAge值分配給這個快取值的Age,currentAge始終增加。

public void Add(string key, TValue value)
       {
           Adjust(key);
           var result = new TrackValue(this, value);
           cache.AddOrUpdate(key, result, (k, o) => result);
       }
       public class TrackValue
       {
           public readonly TValue Value;
           public long Age;
           public TrackValue(LRUCache<TValue> lv, TValue tv)
           {
               Age = Interlocked.Increment(ref lv.currentAge);
               Value = tv;
           }
       }

2:在添加時,如超過最大數量。檢查字典裡是否有ageToDiscard年齡的key,如沒有循環自增檢查,有則刪除、添加成功。

ageToDiscard+maxSize= currentAge ,這樣設計就能在O(1)下保證可以淘汰舊數據,而不是使用鍊錶移動。

public void Adjust(string key)
        {
            while (cache.Count >= maxSize)
            {
                long ageToDelete = Interlocked.Increment(ref ageToDiscard);
                var toDiscard =
                      cache.FirstOrDefault(p => p.Value.Age == ageToDelete);
                if (toDiscard.Key == null)
                    continue;
                TrackValue old;
                cache.TryRemove(toDiscard.Key, out old);
            }
        }

過期刪除策略

大多數情況下,LRU演算法對熱點資料命中率是很高的。 但如果突然大量的偶發性數據訪問,會讓記憶體存放大量冷數據,也就是快取污染。

會造成LRU無法命中熱點數據,導致快取系統命中率急遽下降。也可以使用LRU-K、2Q、MQ等變種演算法來提高命中率。

過期配置

1:我們透過設定、最大過期時間來盡量避免冷資料常駐記憶體。

2:大多數情況每個快取的時間要求不一致的,所以在增加單一key的過期時間。

private TimeSpan maxTime;
public LRUCache(int maxKeySize,TimeSpan maxExpireTime){}
 
 //TrackValue增加创建时间和过期时间
public readonly DateTime CreateTime;
public readonly TimeSpan ExpireTime;

刪除策略

1:關於key過期刪除,最好使用定時刪除了。 這樣可以最快釋放被佔用的內存,但很明顯,大量的定時器對CPU吃不消的。

2:所以我们采用惰性删除、在获取key的时检查是否过期,过期直接删除。

public Tuple<TrackValue, bool> CheckExpire(string key)
        {
            TrackValue result;
            if (cache.TryGetValue(key, out result))
            {
                var age = DateTime.Now.Subtract(result.CreateTime);
                if (age >= maxTime || age >= result.ExpireTime)
                {
                    TrackValue old;
                    cache.TryRemove(key, out old);
                    return Tuple.Create(default(TrackValue), false);
                }
            }
            return Tuple.Create(result, true);
        }

3:惰性删除虽然性能最好,对于冷数据来说,还是没解决缓存污染问题。 所以我们还需定期清理。

比如:开个线程,5分钟去遍历检查key一次。这个策略根据实际场景可配置。

public void Inspection()
        {
            foreach (var item in this)
            {
                CheckExpire(item.Key);
            }
        }

惰性删除+定期删除基本能满足我们需求了。

总结

如果继续完善下去,就是内存数据库的雏形,类似redis。

比如:增加删除key的通知,增加更多数据类型。 本篇也是参考了redis、Orleans的实现。


陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
计算机编程中常见的if语句是什么计算机编程中常见的if语句是什么Jan 29, 2023 pm 04:31 PM

计算机编程中常见的if语句是条件判断语句。if语句是一种选择分支结构,它是依据明确的条件选择选择执行路径,而不是严格按照顺序执行,在编程实际运用中要根据程序流程选择适合的分支语句,它是依照条件的结果改变执行的程序;if语句的简单语法“if(条件表达式){// 要执行的代码;}”。

Python编程:详解命名元组(namedtuple)的使用要点Python编程:详解命名元组(namedtuple)的使用要点Apr 11, 2023 pm 09:22 PM

前言本文继续来介绍Python集合模块,这次主要简明扼要的介绍其内的命名元组,即namedtuple的使用。闲话少叙,我们开始——记得点赞、关注和转发哦~ ^_^创建命名元组Python集合中的命名元组类namedTuples为元组中的每个位置赋予意义,并增强代码的可读性和描述性。它们可以在任何使用常规元组的地方使用,且增加了通过名称而不是位置索引方式访问字段的能力。其来自Python内置模块collections。其使用的常规语法方式为:import collections XxNamedT

如何在Go中进行图像处理?如何在Go中进行图像处理?May 11, 2023 pm 04:45 PM

作为一门高效的编程语言,Go在图像处理领域也有着不错的表现。虽然Go本身的标准库中没有提供专门的图像处理相关的API,但是有一些优秀的第三方库可以供我们使用,比如GoCV、ImageMagick和GraphicsMagick等。本文将重点介绍使用GoCV进行图像处理的方法。GoCV是一个高度依赖于OpenCV的Go语言绑定库,其

PHP8.0中的邮件库PHP8.0中的邮件库May 14, 2023 am 08:49 AM

最近,PHP8.0发布了一个新的邮件库,使得在PHP中发送和接收电子邮件变得更加容易。这个库具有强大的功能,包括构建电子邮件,发送电子邮件,解析电子邮件,获取附件和解决电子邮件获得卡住的问题。在很多项目中,我们都需要使用电子邮件来进行通信和一些必备的业务操作。而PHP8.0中的邮件库可以让我们轻松地实现这一点。接下来,我们将探索这个新的邮件库,并了解如何在我

PHP8.0中的DOMDocumentPHP8.0中的DOMDocumentMay 14, 2023 am 08:18 AM

随着PHP8.0的发布,DOMDocument作为PHP内置的XML解析库,也有了新的变化和增强。DOMDocument在PHP中的重要性不言而喻,尤其在处理XML文档方面,它的功能十分强大,而且使用起来也十分简单。本文将介绍PHP8.0中DOMDocument的新特性和应用。一、DOMDocument概述DOM(DocumentObjectModel)

学Python,还不知道main函数吗学Python,还不知道main函数吗Apr 12, 2023 pm 02:58 PM

Python 中的 main 函数充当程序的执行点,在 Python 编程中定义 main 函数是启动程序执行的必要条件,不过它仅在程序直接运行时才执行,而在作为模块导入时不会执行。要了解有关 Python main 函数的更多信息,我们将从如下几点逐步学习:什么是 Python 函数Python 中 main 函数的功能是什么一个基本的 Python main() 是怎样的Python 执行模式Let’s get started什么是 Python 函数相信很多小伙伴对函数都不陌生了,函数是可

PHP8.0中的Symbol类型PHP8.0中的Symbol类型May 14, 2023 am 08:39 AM

PHP8.0是PHP语言的最新版本,自发布以来已经引发了广泛的关注和争议。其中,最引人瞩目的新特性之一就是Symbol类型。Symbol类型是PHP8.0中新增的一种数据类型,它类似于JavaScript中的Symbol类型,可用于表示独一无二的值。这意味着,两个Symbol类型的值即使完全相同,它们也是不相等的。Symbol类型的使用可以避免在不同的代码段

为拯救童年回忆,开发者决定采用古法编程:用Flash高清重制了一款游戏为拯救童年回忆,开发者决定采用古法编程:用Flash高清重制了一款游戏Apr 11, 2023 pm 10:16 PM

两年多前,Adobe 发布了一则引人关注的公告 —— 将在 2020 年 12 月 31 日终止支持 Flash,宣告了一个时代的结束。一晃两年过去了,Adobe 早已从官方网站中删除了 Flash Player 早期版本的所有存档,并阻止基于 Flash 的内容运行。微软也已经终止对 Adobe Flash Player 的支持,并禁止其在任何 Microsoft 浏览器上运行。Adobe Flash Player 组件于 2021 年 7 月通过 Windows 更新永久删除。当 Flash

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器