Pregunta

I have the following class witch stores a message in a forum

using System;
using System.Collections.Generic;

public partial class ForumMessage
{
    public ForumMessage()
    {
        this.Votes = new HashSet<ForumMessageVote>();
        OnCreated();
    }

    partial void OnCreated();

    public long id { get; set; }
    public int forumId { get; set; }
    public Nullable<long> parentId { get; set; }
    public int memberId { get; set; }
    public int lastModifiedMemberId { get; set; }
    public Nullable<long> lastReplyId { get; set; }
    public string title { get; set; }
    public string body { get; set; }
    public string imagePath { get; set; }
    public Nullable<bool> isSticky { get; set; }
    public Nullable<bool> allowPosts { get; set; }
    public Nullable<bool> allowImages { get; set; }
    public Nullable<bool> allowYoutube { get; set; }
    public Nullable<bool> allowBbCode { get; set; }
    public Nullable<long> totalMessages { get; set; }
    public Nullable<long> totalViews { get; set; }
    public Nullable<long> totalDailyViews { get; set; }
    public Nullable<int> totalVotes { get; set; }
    public Nullable<long> totalScore { get; set; }
    public bool published { get; set; }
    public Nullable<System.DateTime> publishedDate { get; set; }
    public Nullable<System.DateTime> lastModifiedDate { get; set; }
    public Nullable<bool> isTemporary { get; set; }
    public Nullable<System.DateTime> lastReplyDate { get; set; }
    public Nullable<int> lastReplyMemberId { get; set; }
    public Nullable<long> sortByLastReplyId { get; set; }
    public Nullable<bool> containsImage { get; set; }
    public Nullable<bool> containsVideo { get; set; }
    public Nullable<bool> @private { get; set; }

    public virtual Forum Forum { get; set; }
    public virtual ICollection<ForumMessageVote> Votes { get; set; }
    public virtual Member Member { get; set; }
}

Currently I'm caching these objects with Booksleeve by storing them with Json serialization in string keys (at Redis if course) with the following code (simplified version):

            using (var conn = conn.CreateTransaction())
            {
                return conn.Store<ForumMessage>(db, message.id, message);
            }

In my forum application views i utilize most of the above fields because I display lists of the above messages witch belong to forum threads.

In order to fetch the list of ForumMessage classes I use the mget command.

When a user post a new message or when he vote for a message I need to update some of the above fields. When I update I fetch the message via redis get, update the required field/fields (mostly one or two fields) and then I store the update via conn.store booksleeve method.

Currently the forum at peak hours receives about 12 messages / minute and 20 votes / minute(total votes not per message)

I wander if a more optimal solution for the above would be to store the messages in redis hashes because the updates will be faster that way. But In order to use hashes the code that does the initial store at redis will be more complicated (slow) and this code will run on the web server instead of redis server.

Do you think it worth to reimplement the message store/retrieve procedure by using hashes or the solution than I'm using right now will be able to scale fine when for example the rate of message inserts increase with 30 messages/minute?

In essence can you provide some guidelines on how stackoverflow handles this situations?

¿Fue útil?

Solución

Hashes would be the natural fit here, primarily simply because that data structure is aimed at multiple named values that share an overall identity (including expiration etc). There isn't a huge performance difference if you are currently using MGET - for hashes you would simply us HMGET, HGETALL, and HMSET.

I do not see that this changes anything in terms of making it more complicated: you simply populate your intended changes into a Dictionary<string,byte[]> and use .Hashes.Set(...). once rather than calling .Strings.Set multiple times. Likewise, using the varadic form of .Strings.Get(...) is not very different to calling .Hashes.GetAll(...) or the varadic form of .Hashes.Get(...).

Nor do I accept that this code will be any slower - indeed, it is basically identical. Indeed, at the implementation level, a single call to .Hashes.Set involves less overhead in terms of Task etc, since it is a single waitable/awaitable operation.

Currently the forum at peak hours receives about 12 messages / minute and 20 votes / minute(total votes not per message)

That throughput should not present an issue. Redis works happily at many 10s (or 100s) of thousands of messages per second.

Do you think it worth to reimplement the message store/retrieve procedure by using hashes or the solution than I'm using right now will be able to scale fine when for example the rate of message inserts increase with 30 messages/minute?

That message rate should not be problematic. If you are seeing issues, please elaborate. However, the simplest and most appropriate next step would be to simulate some much higher load - see what works.

In essence can you provide some guidelines on how stackoverflow handles this situations?

We generally use a SQL database as our primary data store (although some things are kept solely in redis). We use redis extensively to store processed items as a cache, but since they are not subject to change, we do not store them field-by-field: instead, we use protobuf-net against DTO types and store blobs of data (using the string type, i.e. GET/SET). Further, if the size is above a threshold (and as long as it isn'g going into a set/sorted-set), we do a quick "gzip" test, to see if it gets smaller if we compress it (not everything does): if it does, we store that - so we have the absolute minimum of bandwidth and storage overhead, and very fast processing at store / fetch. For clarity, the reason we do not compress in sets/sorted-sets is that gzip does not guarantee the exact same output each time, which upsets the hashing.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top