Thiết kế website, Thiết kế web, Thiết kế web chuyên nghiệp

Site map|Hỗ trợ

Công nghệ, giải pháp

Hướng dẫn sử dụng redis caching với .NET C

Hướng dẫn sử dụng redis caching với .NET CRedis giúp quản lý cache, tăng tốc độ truy xuất cho website. Đây là công nghệ không thể thiếu đối với các trang web có lưu lượng truy cập lớn.




1. Redis là gì

Redis là một cơ sở dữ liệu nguồn mở lưu trữ theo dạng key-value.  Toàn bộ dữ liệu của Redis được lưu trên bộ nhớ nên tốc độ xử lý cực kỳ nhanh, thậm chí có phần vượt trên memcached. Theo định kỳ dữ liệu từ trên bộ nhớ sẽ được đẩy xuống ổ đĩa.

2. Cài đặt Redis server

- Download tại: https://github.com/dmajkic/redis/downloads  và giải nén C:\Program Files\Redis
- Download Redis service tại https://github.com/kcherenkov/redis-windows-service/downloads, và copy tới C:\Program Files\Redis

Khi đó bạn sẽ có các file như sau:

redis application folder conten

Chạy command để bắt đầu cài đặt:

sc create Redis start= auto DisplayName= Redis binpath= "\"C:\Program Files\Redis\RedisService_1.1.exe\ " \"C:\Program Files\Redis\redis.conf\"" 

Installing redis as windows service

Nếu quá trình cài đặt thành công sẽ xuất hiện service redis:

redis running as a windows service

3. Cầu hình redis server

- Đặt password, IP filtering: Mở file config redis redis.conf

Tìm tới dòng

# requirepass foobared   

Remove ký tự # và thay foobared bằng password mới

Kết quả:


requirepass foobared

Khởi động lại Redis Windows service

Khi đó từ client truy xuất sẽ cần password:

RedisClient client = new RedisClient(serverHost, port, redisPassword);

- Config Redis Server Replication (master-slave):

Redis cho phép bạn phân tán cache trên nhiều server với nhiều chế độ: read/write hoặc read nhưng không write,..

Để thực hiện bạn tìm đến dòng:

# slaveof <masterip> <masterport>

Thay thế bằng thông tin server slave. VD:

slaveof 192.168.1.1 6379

Với server master bạn có thể đặt password tại dòng:

# masterauth <master-password>

VD: masterauth mastpassword

Quá trình cài đặt và config hoàn tất. Giờ bạn có thể bắt đầu sử dụng chúng từ các ứng dụng.

4. Truy xuất redis cache từ C#

- Download và add thư viện ServiceStack.Redis từ NuGet :

Ví dụ minh họa Get và set dữ liệu:

string host = "localhost"; string elementKey = "testKeyRedis";  using (RedisClient redisClient = new RedisClient(host)) {       if (redisClient.Get<string>(elementKey) == null)       {            // adding delay to see the difference            Thread.Sleep(5000);             // save value in cache            redisClient.Set(elementKey, "some cached value");       }       // get value from the cache by key       message = "Item value is: " + redisClient.Get<string>("some cached value");  }

5. ASP.NET Session State with Redis

Để cấu hình ASP.NET session state sử dụng redis thì cần add thêm file RedisSessionStateProvider.cs vào project (download tại https://github.com/chadman/redis-service-provider/raw/master/RedisProvider/SessionProvider/RedisSessionProvider.cs)

Sau đó cầu hình trong web.config:

<sessionstate timeout="1" mode="Custom" customprovider="RedisSessionStateProvider" cookieless="false"> <providers> <add name="RedisSessionStateProvider" writeexceptionstoeventlog="false" type="RedisProvider.SessionProvider.CustomServiceProvider" server="localhost" port="6379" password="pasword"> </add> </providers> </sessionstate>

6.
Redis Sets and Lists

Ví dụ minh họa:

string host = "localhost"; using (var redisClient = new RedisClient(host)) { //Create a 'strongly-typed' API that makes all Redis Value operations to apply against Phones IRedisTypedClient<phone> redis = redisClient.As<phone>(); IRedisList<phone> mostSelling = redis.Lists["urn:phones:mostselling"]; IRedisList<phone> oldCollection = redis.Lists["urn:phones:oldcollection"]; Person phonesOwner = new Person { Id = 7, Age = 90, Name = "OldOne", Profession = "sportsmen", Surname = "OldManSurname" }; // adding new items to the list mostSelling.Add(new Phone { Id = 5, Manufacturer = "Sony", Model = "768564564566", Owner = phonesOwner }); mostSelling.Add(new Phone { Id = 8, Manufacturer = "Motorolla", Model = "324557546754", Owner = phonesOwner }); var upgradedPhone = new Phone { Id = 3, Manufacturer = "LG", Model = "634563456", Owner = phonesOwner }; mostSelling.Add(upgradedPhone); // remove item from the list oldCollection.Remove(upgradedPhone); // find objects in the cache IEnumerable<phone> LGPhones = mostSelling.Where(ph => ph.Manufacturer == "LG"); // find specific Phone singleElement = mostSelling.FirstOrDefault(ph => ph.Id == 8); //reset sequence and delete all lists redis.SetSequence(0); redisClient.Remove("urn:phones:mostselling"); redisClient.Remove("urn:phones:oldcollection"); }

--------------------------

/// <summary> /// Gets or sets the Redis Manager. The built-in IoC used with ServiceStack autowires this property. /// </summary> IRedisClientsManager RedisManager { get; set; } /// <summary> /// Delete question by performing compensating actions to /// StoreQuestion() to keep the datastore in a consistent state /// </summary> /// <param name="questionId"> public void DeleteQuestion(long questionId) { using (var redis = RedisManager.GetClient()) { var redisQuestions = redis.As<question>(); var question = redisQuestions.GetById(questionId); if (question == null) return; //decrement score in tags list question.Tags.ForEach(tag => redis.IncrementItemInSortedSet("urn:tags", tag, -1)); //remove all related answers redisQuestions.DeleteRelatedEntities<answer>(questionId); //remove this question from user index redis.RemoveItemFromSet("urn:user>q:" + question.UserId, questionId.ToString()); //remove tag => questions index for each tag question.Tags.ForEach("urn:tags>q:" + tag.ToLower(), questionId.ToString())); redisQuestions.DeleteById(questionId); } } public void StoreQuestion(Question question) { using (var redis = RedisManager.GetClient()) { var redisQuestions = redis.As<question>(); if (question.Tags == null) question.Tags = new List<string>(); if (question.Id == default(long)) { question.Id = redisQuestions.GetNextSequence(); question.CreatedDate = DateTime.UtcNow; //Increment the popularity for each new question tag question.Tags.ForEach(tag => redis.IncrementItemInSortedSet("urn:tags", tag, 1)); } redisQuestions.Store(question); redisQuestions.AddToRecentsList(question); redis.AddItemToSet("urn:user>q:" + question.UserId, question.Id.ToString()); //Usage of tags - Populate tag => questions index for each tag question.Tags.ForEach(tag => redis.AddItemToSet ("urn:tags>q:" + tag.ToLower(), question.Id.ToString())); } } /// <summary> /// Delete Answer by performing compensating actions to /// StoreAnswer() to keep the datastore in a consistent state /// </summary> /// <param name="questionId"> /// <param name="answerId"> public void DeleteAnswer(long questionId, long answerId) { using (var redis = RedisManager.GetClient()) { var answer = redis.As<question>().GetRelatedEntities<answer> (questionId).FirstOrDefault(x => x.Id == answerId); if (answer == null) return; redis.As<question>().DeleteRelatedEntity<answer>(questionId, answerId); //remove user => answer index redis.RemoveItemFromSet("urn:user>a:" + answer.UserId, answerId.ToString()); } } public void StoreAnswer(Answer answer) { using (var redis = RedisManager.GetClient()) { if (answer.Id == default(long)) { answer.Id = redis.As<answer>().GetNextSequence(); answer.CreatedDate = DateTime.UtcNow; } //Store as a 'Related Answer' to the parent Question redis.As<question>().StoreRelatedEntities(answer.QuestionId, answer); //Populate user => answer index redis.AddItemToSet("urn:user>a:" + answer.UserId, answer.Id.ToString()); } } public List<answer> GetAnswersForQuestion(long questionId) { using (var redis = RedisManager.GetClient()) { return redis.As<question>().GetRelatedEntities<answer>(questionId); } } public void VoteQuestionUp(long userId, long questionId) { //Populate Question => User and User => Question set indexes in a single transaction RedisManager.ExecTrans(trans => { //Register upvote against question and remove any downvotes if any trans.QueueCommand(redis => redis.AddItemToSet("urn:q>user+:" + questionId, userId.ToString())); trans.QueueCommand(redis => redis.RemoveItemFromSet("urn:q>user-:" + questionId, userId.ToString())); //Register upvote against user and remove any downvotes if any trans.QueueCommand(redis => redis.AddItemToSet("urn:user>q+:" + userId, questionId.ToString())); trans.QueueCommand(redis => redis.RemoveItemFromSet("urn:user>q-:" + userId, questionId.ToString())); }); } public void VoteQuestionDown(long userId, long questionId) { //Populate Question => User and User => Question set indexes in a single transaction RedisManager.ExecTrans(trans => { //Register downvote against question and remove any upvotes if any trans.QueueCommand(redis => redis.AddItemToSet("urn:q>user-:" + questionId, userId.ToString())); trans.QueueCommand(redis => redis.RemoveItemFromSet("urn:q>user+:" + questionId, userId.ToString())); //Register downvote against user and remove any upvotes if any trans.QueueCommand(redis => redis.AddItemToSet"urn:user>q-:" + userId, questionId.ToString())); trans.QueueCommand(redis => redis.RemoveItemFromSet("urn:user>q+:" + userId, questionId.ToString())); }); } public void VoteAnswerUp(long userId, long answerId) { //Populate Question => User and User => Question set indexes in a single transaction RedisManager.ExecTrans(trans => { //Register upvote against answer and remove any downvotes if any trans.QueueCommand(redis => redis.AddItemToSet("urn:a>user+:" + answerId, userId.ToString())); trans.QueueCommand(redis => redis.RemoveItemFromSet("urn:a>user-:" + answerId, userId.ToString())); //Register upvote against user and remove any downvotes if any trans.QueueCommand(redis => redis.AddItemToSet("urn:user>a+:" + userId, answerId.ToString())); trans.QueueCommand(redis => redis.RemoveItemFromSet("urn:user>a-:" + userId, answerId.ToString())); }); } public void VoteAnswerDown(long userId, long answerId) { //Populate Question => User and User => Question set indexes in a single transaction RedisManager.ExecTrans(trans => { //Register downvote against answer and remove any upvotes if any trans.QueueCommand(redis => redis.AddItemToSet("urn:a>user-:" + answerId, userId.ToString())); trans.QueueCommand(redis => redis.RemoveItemFromSet("urn:a>user+:" + answerId, userId.ToString())); //Register downvote against user and remove any upvotes if any trans.QueueCommand(redis => redis.AddItemToSet("urn:user>a-:" + userId, answerId.ToString())); trans.QueueCommand(redis => redis.RemoveItemFromSet("urn:user>a+:" + userId, answerId.ToString())); }); } public QuestionResult GetQuestion(long questionId) { var question = RedisManager.ExecAs<question> (redisQuestions => redisQuestions.GetById(questionId)); if (question == null) return null; var result = ToQuestionResults(new[] { question })[0]; var answers = GetAnswersForQuestion(questionId); var uniqueUserIds = answers.ConvertAll(x => x.UserId).ToHashSet(); var usersMap = GetUsersByIds(uniqueUserIds).ToDictionary(x => x.Id); result.Answers = answers.ConvertAll(answer => new AnswerResult { Answer = answer, User = usersMap[answer.UserId] }); return result; } public List<user> GetUsersByIds(IEnumerable<long> userIds) { return RedisManager.ExecAs<user>(redisUsers => redisUsers.GetByIds(userIds)).ToList(); } public QuestionStat GetQuestionStats(long questionId) { using (var redis = RedisManager.GetReadOnlyClient()) { var result = new QuestionStat { VotesUpCount = redis.GetSetCount("urn:q>user+:" +questionId), VotesDownCount = redis.GetSetCount("urn:q>user-:" + questionId) }; result.VotesTotal = result.VotesUpCount - result.VotesDownCount; return result; } } public List<tag> GetTagsByPopularity(int skip, int take) { using (var redis = RedisManager.GetReadOnlyClient()) { var tagEntries = redis.GetRangeWithScoresFromSortedSetDesc("urn:tags", skip, take); var tags = tagEntries.ConvertAll(kvp => new Tag { Name = kvp.Key, Score = (int)kvp.Value }); return tags; } } public SiteStats GetSiteStats() { using (var redis = RedisManager.GetClient()) { return new SiteStats { QuestionsCount = redis.As<question>().TypeIdsSet.Count, AnswersCount = redis.As<answer>().TypeIdsSet.Count, TopTags = GetTagsByPopularity(0, 10) }; } }

Chúc các bạn thành công!

Bình luận