Rumah pembangunan bahagian belakang tutorial php 编程技术缓存写法(三)

编程技术缓存写法(三)

Nov 30, 2016 am 09:27 AM

上次我们说了多级缓存,本章详细介绍下内存缓存该如何设计。

一:分析设计

假设有个项目有一定并发量,要用到多级缓存,如下:

2253.jpg

在实际设计一个内存缓存前,我们需要考虑的问题:

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;
       }
   }
Salin selepas log masuk

上面定义了 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;
           }
       }
Salin selepas log masuk

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);
            }
        }
Salin selepas log masuk

过期删除策略

大多数情况下,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;
Salin selepas log masuk

删除策略

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);
        }
Salin selepas log masuk

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

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

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

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

总结

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

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


Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Alih keluar nilai pendua daripada tatasusunan PHP menggunakan ungkapan biasa Alih keluar nilai pendua daripada tatasusunan PHP menggunakan ungkapan biasa Apr 26, 2024 pm 04:33 PM

Cara mengalih keluar nilai pendua daripada tatasusunan PHP menggunakan ungkapan biasa: Gunakan ungkapan biasa /(.*)(.+)/i untuk memadankan dan menggantikan pendua. Lelaran melalui elemen tatasusunan dan semak padanan menggunakan preg_match. Jika ia sepadan, langkau nilai jika tidak, tambahkannya pada tatasusunan baharu tanpa nilai pendua.

Untuk apa pengaturcaraan dan apakah kegunaan mempelajarinya? Untuk apa pengaturcaraan dan apakah kegunaan mempelajarinya? Apr 28, 2024 pm 01:34 PM

1. Pengaturcaraan boleh digunakan untuk membangunkan pelbagai perisian dan aplikasi, termasuk tapak web, aplikasi mudah alih, permainan dan alat analisis data. Bidang aplikasinya sangat luas, meliputi hampir semua industri, termasuk penyelidikan saintifik, penjagaan kesihatan, kewangan, pendidikan, hiburan, dll. 2. Pembelajaran pengaturcaraan boleh membantu kita meningkatkan kemahiran menyelesaikan masalah dan kemahiran berfikir logik. Semasa pengaturcaraan, kita perlu menganalisis dan memahami masalah, mencari penyelesaian dan menterjemahkannya ke dalam kod. Cara berfikir ini boleh memupuk kebolehan analitikal dan abstrak kita dan meningkatkan keupayaan kita untuk menyelesaikan masalah praktikal.

Bina aplikasi berasaskan pelayar dengan Golang Bina aplikasi berasaskan pelayar dengan Golang Apr 08, 2024 am 09:24 AM

Bina aplikasi berasaskan pelayar dengan Golang Golang digabungkan dengan JavaScript untuk membina pengalaman bahagian hadapan yang dinamik. Pasang Golang: Lawati https://golang.org/doc/install. Sediakan projek Golang: Cipta fail bernama main.go. Menggunakan GorillaWebToolkit: Tambahkan kod GorillaWebToolkit untuk mengendalikan permintaan HTTP. Cipta templat HTML: Cipta index.html dalam subdirektori templat, yang merupakan templat utama.

Penyelesaian Masalah dengan Python: Buka Kunci Penyelesaian Berkuasa sebagai Pengekod Pemula Penyelesaian Masalah dengan Python: Buka Kunci Penyelesaian Berkuasa sebagai Pengekod Pemula Oct 11, 2024 pm 08:58 PM

Pythonmemperkasakan pemula dalam menyelesaikan masalah.Sintaksnya yang mesra pengguna, perpustakaan luas, dan ciri-ciri seperti pembolehubah, pernyataan bersyarat, dan pembangunan kod yang cekap boleh dilonggarkan. Daripada mengurus data untuk mengawal aliran program dan melaksanakan tugasan berulang, Pythonprovid

Koleksi teka-teki pengaturcaraan C++: merangsang pemikiran dan meningkatkan kemahiran pengaturcaraan Koleksi teka-teki pengaturcaraan C++: merangsang pemikiran dan meningkatkan kemahiran pengaturcaraan Jun 01, 2024 pm 10:26 PM

Teka-teki pengaturcaraan C++ meliputi algoritma dan konsep struktur data seperti jujukan Fibonacci, faktorial, jarak Hamming, nilai maksimum dan minimum tatasusunan, dll. Dengan menyelesaikan teka-teki ini, anda boleh menyatukan pengetahuan C++ dan meningkatkan pemahaman algoritma dan kemahiran pengaturcaraan.

Dapatkan modul Go dengan cepat dan mudah dengan Go Get Dapatkan modul Go dengan cepat dan mudah dengan Go Get Apr 07, 2024 pm 09:48 PM

Melalui GoGet, anda boleh mendapatkan modul Go dengan cepat dan mudah Langkah-langkahnya adalah seperti berikut: Jalankan dalam terminal: goget[module-path], dengan modul-path ialah laluan modul. GoGet memuat turun modul dan kebergantungannya secara automatik. Lokasi pemasangan ditentukan oleh pembolehubah persekitaran GOPATH.

Lepaskan Pengaturcara Dalaman Anda: C untuk Pemula Mutlak Lepaskan Pengaturcara Dalaman Anda: C untuk Pemula Mutlak Oct 11, 2024 pm 03:50 PM

C ialah bahasa yang sesuai untuk pemula untuk mempelajari pengaturcaraan, dan kelebihannya termasuk kecekapan, serba boleh dan mudah alih. Mempelajari bahasa C memerlukan: Memasang pengkompil C (seperti MinGW atau Cygwin) Memahami pembolehubah, jenis data, pernyataan bersyarat dan pernyataan gelung Menulis program pertama yang mengandungi fungsi utama dan fungsi printf() Berlatih melalui kes praktikal (seperti mengira purata) C pengetahuan bahasa

Kunci Pengekodan: Membuka Kunci Kuasa Python untuk Pemula Kunci Pengekodan: Membuka Kunci Kuasa Python untuk Pemula Oct 11, 2024 pm 12:17 PM

Python ialah bahasa pengenalan pengaturcaraan yang ideal untuk pemula melalui kemudahan pembelajaran dan ciri yang berkuasa. Asasnya termasuk: Pembolehubah: digunakan untuk menyimpan data (nombor, rentetan, senarai, dll.). Jenis data: Mentakrifkan jenis data dalam pembolehubah (integer, titik terapung, dll.). Operator: digunakan untuk operasi matematik dan perbandingan. Aliran kawalan: Kawal aliran pelaksanaan kod (penyataan bersyarat, gelung).

See all articles