iT邦幫忙

2024 iThome 鐵人賽

DAY 22
0

Hi all, 來到第22天 有鑒於昨天將 redis 應用在專案上,突然有個發想,那就是假設這個專案在以後面臨到高流量的情況怎麼辦?

照目前的設計來說,我們確實可以在的方面減少對於 DB的呼叫,但在的這一塊卻是呼叫完DB再更新 Cache。基於這個因素,小弟有個想法,那就是 資料層直接對 Redis 做讀寫,意思就是每個 request 對於資料的讀寫都是直接對 Redis 進行呼叫,並在固定時間內將 Redis 上的資料放進 DB。

GPT 評價

By Request

使用 Redis 快取每一個資料項目的設計可以大幅提升資料讀取的效能,特別是在高讀取場景下。然而,在實作這個策略時,需要考慮 Redis 的內存使用、鍵管理、一致性問題以及過期策略。根據你的業務需求,調整 Redis 的快取策略,將能夠充分利用 Redis 的優勢,同時避免潛在的問題。

New Solution

這種設計思路(批量更新策略)在高流量和高併發場景下有著不錯的效能和可擴展性。它能夠顯著減少資料庫的負擔,提高系統的整體效能。然而,在實現這種架構時需要考慮資料一致性、錯誤恢復、內存管理和回寫策略等挑戰。

為了達到最佳效果,建議進行以下優化:

  • 使用 Redis 的持久化機制(如 RDB 和 AOF)來保護資料。
  • 設計合理的回寫頻率和批量處理機制。
  • 實施有效的併發控制策略,防止資料競爭和不一致問題。
  • 設置 Redis 的內存管理策略,防止內存溢出或過度消耗。

弄髒手時間

那這次的目標蠻明確了, 來列一下驗收條件

  • 讓資料更新時,直接向 redis 裡的資料進行修改
  • 設定一個 time interval function 定時向 DB 放資料

RedisTiemIntervalService

public class RedisTimeIntervalService(IConnectionMultiplexer connectionMultiplexer, IChainRepository chainRepository): IHostedService, IDisposable
{
    private readonly IDatabase _redisService = connectionMultiplexer.GetDatabase();
    private Timer? _timer;

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _timer = new Timer(PushRedisDataToDb, null, TimeSpan.Zero, 
            TimeSpan.FromSeconds(5));

        return Task.CompletedTask;
    }

    private void PushRedisDataToDb(object? state)
    {
        var fromRedis = _redisService.StringGet("data");
        
        if (fromRedis == "")
        {
            return ;
        }
        
        var blocks = JsonSerializer.Deserialize<List<Block>>(fromRedis);
        chainRepository.SyncCacheToDb(blocks);
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _timer.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer.Dispose();
    }
}

Register Service

builder.Services.AddHostedService<RedisTimeIntervalService>();

Repository

public void SyncCacheToDb(List<Block> blocks)
{
    foreach (var block in _blocks)
    {
        var firstOrDefault = blocks.FirstOrDefault(x=> x.Id == block.Id);
        if (firstOrDefault != null)
        {
            block.Data = firstOrDefault.Data;
            block.PreviousHash = firstOrDefault.PreviousHash;
            block.Nonce = firstOrDefault.Nonce;
            block.Hash = firstOrDefault.Hash;
            block.TimeStamp = firstOrDefault.TimeStamp;
            block.ChameleonSignature = firstOrDefault.ChameleonSignature;
            continue;
        }
        _blocks.AddAsync(firstOrDefault!);
    }
    
    blockchainDbContext.SaveChangesAsync();
}

Conclusion

今天把專案原先透過 by request 透過 redis 再呼叫 db 轉變為批量寫進 db,另外再讓 request 取得資料的方式從db為主改為 redis為主。 但也不是說這樣個樣子是最好的,還是需要看使用場景,因此我這邊會開 branch來做個紀錄。

今天就先這樣,明天再來看看如果遇到併發時開怎麼做處理~~

結語: 昨晚不小喝太多~~~


上一篇
Day21 Apply Redis as Cache Service
下一篇
Day 23 Docker-compose 專案帶著跑
系列文
Side-Project:: 為自己打造個可編輯的區塊鏈30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言