簡體   English   中英

通過protobufnet從Redis反序列化大量用戶定義的對象時出現性能問題

[英]Performance issue while deserializing large collection of user defined object from Redis via protobufnet

問題:在反序列化從Redis接收的字節時面臨性能下降。

我正在使用REDIS在ASP.NET Web應用程序中分發緩存。

為了與我的應用程序中的Redis對話,我使用StackExchange.Redis

為了序列化/反序列化從/到DTO到/從服務器收到的字節,我使用的是protobuf-net

我的目標是在Redis中存儲100,000個用戶的字典(Dictionary(int,User)),並在單個請求上多次將其取回

該詞典將位於MyContext.Current.Users屬性下。 該詞典的關鍵字是用戶標識,值是完整的dto。 我現在遇到的問題是,從字節反序列化列表100,000個用戶需要花費1.5-2秒(Redis給我字節)。 我必須在請求中多次使用該屬性。

public Dictionary<int, User> Users
{
    get
    {
        // Get users from Redis cache.
        // Save it in Redis cache if it is not there before and then get it.
    }
}

用戶是我的上下文包裝器類中公開的屬性。

這是我為用戶准備的DTO(此DTO具有100多個屬性):

[ProtoContract]
public class User
{
    [ProtoMember(1)]
    public string UserName { get; set; }

    [ProtoMember(2)]
    public string UserID { get; set; }

    [ProtoMember(3)]
    public string FirstName { get; set; }

    .
    .
    .
    .
}

這是我用來在StackExchange.Redis的幫助下與Redis交談的代碼的片段:

在存儲時-將DTO轉換為字節,以便可以將其存儲到Redis中:

db.StringSet(cacheKey,bytes,slidingExpiration)

命令:

private byte[] ObjectToByteArrayFromProtoBuff(Object obj)
{
    if (obj == null)
    {
        return null;
    }

    using (MemoryStream ms = new MemoryStream())
    {
        Serializer.Serialize(ms, obj);
        return ms.ToArray();
    }
}

提取時-將字節轉換為DTO,從

db.StringGet(cacheKey);

命令:

private T ByteArrayToObjectFromProtoBuff<T>(byte[] arrBytes)
{
    if (arrBytes != null)
    {
        using (MemoryStream ms = new MemoryStream(arrBytes))
        {
            var obj = Serializer.Deserialize<T>(ms);
            return obj;
        }
    }
    return default(T);
}

這是ANTS Performance Profiler的屏幕截圖,顯示了protobuf-net從Redis提供的字節中反序列化100,000個用戶所花費的時間。

在此處輸入圖片說明

如您所見,將字節反序列化為用戶字典(詞典用戶)所需的平均時間約為1.5至2秒,這太長了,因為我在很多地方都使用該屬性從該字典中獲取用戶信息。

您能告訴我我在做什么錯嗎?

每次將Redis的100,000個用戶列表反序列化到應用程序中然后使用它是否很好? (每個請求還必須在任何使用Users屬性的地方反序列化)。

將用戶的字典/集合/列表或任何其他大型集合按字節存儲到Redis中,然后在每次使用時通過反序列化將其取回是否正確?

根據以下文章, Stack Exchange是否使用緩存?如果使用緩存,如何使用緩存? 我知道StackExchange大量使用Redis。 我相信我的100,000個用戶要少得多,它的大小(大約60-80 MB)遠遠小於StackExchange和其他站點(FB等)的大小。 StackOverflow為何如此快速地反序列化這么大的用戶/頭等問題列表以及許多其他項(在緩存中)?

我不能在高速緩存下使用DTO(該列表中的每個項目都具有100多個屬性)的100,000個用戶的詞典,並在單個請求或每個請求中多次對它進行反序列化嗎?

當我使用HttpRuntime.Cache作為緩存提供程序時,該列表/字典沒有任何問題,但是當我切換到Redis時,反序列化部分會造成障礙,因為它仍然很慢。

我想在這篇文章中添加更多細節。 以前我使用BinaryFormatter反序列化該列表,它比我現在使用的protobufnet慢近10倍。 但是,即使使用protobufnet,從字節反序列化那些用戶平均也要花費1.5到2秒,這仍然很慢,因為該屬性必須在代碼中多次使用。

是的,如果您嘗試傳輸大量的許多對象,則將始終需要為整個圖形支付帶寬+反序列化成本。 關鍵是:不要這樣做。 每個請求多次獲取100,000個用戶的列表似乎是完全沒有必要的,並且在很大程度上是性能瓶頸。

有兩種常見方法:

  • 使用大型對象( Dictionary<,> ),但僅偶爾獲取-如:在后台,每隔5分鍾,或者如果您知道它已通過pub / sub進行了更改
  • 僅處理每個請求所需的謹慎對象,其余的留在redis服務器上; 每個請求最多只能獲取一次

哪種方法都可以,並且您希望使用哪種方法取決於您的請求率與數據更改率之比以及所需數據的最新程度。 例如,對於第二種方法,您可以考慮使用redis hash ,其中的鍵與您現在使用的鍵非常相似,hash-slot鍵是int (或其中的某些字符串/二進制表示形式),而hash -slot值是單個 DyveUser實例的序列化形式。 在這里使用散列 (相對於每個用戶字符串)的優點是,您仍然可以通過redis散列命令(例如hgetall )一次獲取/清除/等所有用戶。 SE.Redis中具有Hash*前綴的所有必需的哈希操作均可用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM