Redis 의 List 형식 을 자세히 설명 합 니 다.

24368 단어 RedisList유형
이 시 리 즈 는 Redis 분포 식 캐 시 를 공유 할 것 입 니 다.이 장 에 서 는 Redis 의 List 유형 과 Redis 를 어떻게 사용 하여 블 로그 데이터 페이지,생산자 소비자 모델 과 게시 구독 등 문 제 를 해결 하 는 지 간단하게 소개 합 니 다.
Redis List 의 실현 은 양 방향 링크 입 니 다.즉,역방향 검색 과 옮 겨 다 니 는 것 을 지원 하고 조작 하기에 더욱 편리 합 니 다.그러나 일부 추가 메모리 비용 을 가 져 왔 습 니 다.Redis 내부 의 많은 실현 은 발송 버퍼 대기 열 등 도 모두 이 데이터 구 조 를 사용 합 니 다.
List 유형 은 주로 대기 열 과 스 택,먼저 나 가 고 나중에 먼저 나 가 는 데 사 용 됩 니 다.
저장 형식:key--LinkList

먼저 레 디 스에 서 List 형식 과 관련 된 API 를 보 여 드 리 겠 습 니 다.

using System;
using System.Collections.Generic;
using ServiceStack.Redis;

namespace TianYa.Redis.Service
{
 /// <summary>
 /// Redis List          ,            ,     ,              ,
 /// Redis       ,                   。 
 /// </summary>
 public class RedisListService : RedisBase
 {
  #region Queue  (    )

  /// <summary>
  ///   
  /// </summary>
  /// <param name="listId">  Id</param>
  /// <param name="value">    </param>
  public void EnqueueItemOnList(string listId, string value)
  {
   base._redisClient.EnqueueItemOnList(listId, value);
  }

  /// <summary>
  ///   
  /// </summary>
  /// <param name="listId">  Id</param>
  /// <returns>    </returns>
  public string DequeueItemFromList(string listId)
  {
   return base._redisClient.DequeueItemFromList(listId);
  }

  /// <summary>
  ///   (  )
  /// </summary>
  /// <param name="listId">  Id</param>
  /// <param name="timeOut">    (    )</param>
  /// <returns>    </returns>
  public string BlockingDequeueItemFromList(string listId, TimeSpan? timeOut)
  {
   return base._redisClient.BlockingDequeueItemFromList(listId, timeOut);
  }

  /// <summary>
  ///    list   (  )
  /// </summary>
  /// <param name="listIds">  Id</param>
  /// <param name="timeOut">    (    )</param>
  /// <returns>      listId & Item</returns>
  public ItemRef BlockingDequeueItemFromLists(string[] listIds, TimeSpan? timeOut)
  {
   return base._redisClient.BlockingDequeueItemFromLists(listIds, timeOut);
  }

  #endregion Queue  (    )

  #region Stack (    )

  /// <summary>
  ///   
  /// </summary>
  /// <param name="listId">  Id</param>
  /// <param name="value">    </param>
  public void PushItemToList(string listId, string value)
  {
   base._redisClient.PushItemToList(listId, value);
  }

  /// <summary>
  ///   ,       
  /// </summary>
  /// <param name="listId">  Id</param>
  /// <param name="value">    </param>
  /// <param name="expireAt">    </param>
  public void PushItemToList(string listId, string value, DateTime expireAt)
  {
   base._redisClient.PushItemToList(listId, value);
   base._redisClient.ExpireEntryAt(listId, expireAt);
  }

  /// <summary>
  ///   ,       
  /// </summary>
  /// <param name="listId">  Id</param>
  /// <param name="value">    </param>
  /// <param name="expireIn">    </param>
  public void PushItemToList(string listId, string value, TimeSpan expireIn)
  {
   base._redisClient.PushItemToList(listId, value);
   base._redisClient.ExpireEntryIn(listId, expireIn);
  }

  /// <summary>
  ///   
  /// </summary>
  /// <param name="listId">  Id</param>
  /// <returns>    </returns>
  public string PopItemFromList(string listId)
  {
   return base._redisClient.PopItemFromList(listId);
  }

  /// <summary>
  ///   (  )
  /// </summary>
  /// <param name="listId">  Id</param>
  /// <param name="timeOut">    (    )</param>
  /// <returns>    </returns>
  public string BlockingPopItemFromList(string listId, TimeSpan? timeOut)
  {
   return base._redisClient.BlockingPopItemFromList(listId, timeOut);
  }

  /// <summary>
  ///    list      (  )
  /// </summary>
  /// <param name="listIds">  Id</param>
  /// <param name="timeOut">    (    )</param>
  /// <returns>      listId & Item</returns>
  public ItemRef BlockingPopItemFromLists(string[] listIds, TimeSpan? timeOut)
  {
   return base._redisClient.BlockingPopItemFromLists(listIds, timeOut);
  }

  /// <summary>
  ///  fromListId        toListId  
  /// </summary>
  /// <param name="fromListId">    Id</param>
  /// <param name="toListId">    Id</param>
  /// <returns>      </returns>
  public string PopAndPushItemBetweenLists(string fromListId, string toListId)
  {
   return base._redisClient.PopAndPushItemBetweenLists(fromListId, toListId);
  }

  /// <summary>
  ///  fromListId        toListId  (  )
  /// </summary>
  /// <param name="fromListId">    Id</param>
  /// <param name="toListId">    Id</param>
  /// <param name="timeOut">    (    )</param>
  /// <returns>      </returns>
  public string BlockingPopAndPushItemBetweenLists(string fromListId, string toListId, TimeSpan? timeOut)
  {
   return base._redisClient.BlockingPopAndPushItemBetweenLists(fromListId, toListId, timeOut);
  }

  #endregion Stack (    )

  #region   

  /// <summary>
  ///  list    value 
  /// </summary>
  public void PrependItemToList(string listId, string value)
  {
   base._redisClient.PrependItemToList(listId, value);
  }

  /// <summary>
  ///  list    value ,       
  /// </summary> 
  public void PrependItemToList(string listId, string value, DateTime expireAt)
  {
   base._redisClient.PrependItemToList(listId, value);
   base._redisClient.ExpireEntryAt(listId, expireAt);
  }

  /// <summary>
  ///  list    value ,       
  /// </summary>  
  public void PrependItemToList(string listId, string value, TimeSpan expireIn)
  {
   base._redisClient.PrependItemToList(listId, value);
   base._redisClient.ExpireEntryIn(listId, expireIn);
  }

  /// <summary>
  ///  list   value 
  /// </summary>  
  public void AddItemToList(string listId, string value)
  {
   base._redisClient.AddItemToList(listId, value);
  }

  /// <summary>
  ///  list   value ,       
  /// </summary> 
  public void AddItemToList(string listId, string value, DateTime expireAt)
  {
   base._redisClient.AddItemToList(listId, value);
   base._redisClient.ExpireEntryAt(listId, expireAt);
  }

  /// <summary>
  ///  list   value ,       
  /// </summary> 
  public void AddItemToList(string listId, string value, TimeSpan expireIn)
  {
   base._redisClient.AddItemToList(listId, value);
   base._redisClient.ExpireEntryIn(listId, expireIn);
  }

  /// <summary>
  ///  list     value 
  /// </summary> 
  public void AddRangeToList(string listId, List<string> values)
  {
   base._redisClient.AddRangeToList(listId, values);
  }

  /// <summary>
  ///  list     value ,       
  /// </summary> 
  public void AddRangeToList(string listId, List<string> values, DateTime expireAt)
  {
   base._redisClient.AddRangeToList(listId, values);
   base._redisClient.ExpireEntryAt(listId, expireAt);
  }

  /// <summary>
  ///  list     value ,       
  /// </summary> 
  public void AddRangeToList(string listId, List<string> values, TimeSpan expireIn)
  {
   base._redisClient.AddRangeToList(listId, values);
   base._redisClient.ExpireEntryIn(listId, expireIn);
  }

  #endregion   

  #region    

  /// <summary>
  ///     list        
  /// </summary> 
  public long GetListCount(string listId)
  {
   return base._redisClient.GetListCount(listId);
  }

  /// <summary>
  ///     list          
  /// </summary> 
  public List<string> GetAllItemsFromList(string listId)
  {
   return base._redisClient.GetAllItemsFromList(listId);
  }

  /// <summary>
  ///     list    startingFrom endingAt    
  /// </summary> 
  public List<string> GetRangeFromList(string listId, int startingFrom, int endingAt)
  {
   return base._redisClient.GetRangeFromList(listId, startingFrom, endingAt);
  }

  #endregion    

  #region   

  /// <summary>
  ///     list ,listId/value,       ,        
  /// </summary> 
  public long RemoveItemFromList(string listId, string value)
  {
   return base._redisClient.RemoveItemFromList(listId, value);
  }

  /// <summary>
  ///    list         ,        
  /// </summary> 
  public string RemoveEndFromList(string listId)
  {
   return base._redisClient.RemoveEndFromList(listId);
  }

  /// <summary>
  ///    list         ,        
  /// </summary> 
  public string RemoveStartFromList(string listId)
  {
   return base._redisClient.RemoveStartFromList(listId);
  }

  #endregion   

  #region   

  /// <summary>
  ///     ,  list  
  /// </summary>
  /// <param name="listId">  Id</param>
  /// <param name="keepStartingFrom">    </param>
  /// <param name="keepEndingAt">    </param>
  public void TrimList(string listId, int keepStartingFrom, int keepEndingAt)
  {
   base._redisClient.TrimList(listId, keepStartingFrom, keepEndingAt);
  }

  #endregion   

  #region     

  /// <summary>
  ///   
  /// </summary>
  /// <param name="channel">  </param>
  /// <param name="message">  </param>
  public void Publish(string channel, string message)
  {
   base._redisClient.PublishMessage(channel, message);
  }

  /// <summary>
  ///   
  /// </summary>
  /// <param name="channel">  </param>
  /// <param name="actionOnMessage"></param>
  public void Subscribe(string channel, Action<string, string, IRedisSubscription> actionOnMessage)
  {
   var subscription = base._redisClient.CreateSubscription();
   subscription.OnSubscribe = c =>
   {
    Console.WriteLine($"    {c}");
    Console.WriteLine();
   };
   //    
   subscription.OnUnSubscribe = c =>
   {
    Console.WriteLine($"     {c}");
    Console.WriteLine();
   };
   subscription.OnMessage += (c, s) =>
   {
    actionOnMessage(c, s, subscription);
   };
   Console.WriteLine($"       {channel}");
   subscription.SubscribeToChannels(channel); //blocking
  }

  /// <summary>
  ///     
  /// </summary>
  /// <param name="channel">  </param>
  public void UnSubscribeFromChannels(string channel)
  {
   var subscription = base._redisClient.CreateSubscription();
   subscription.UnSubscribeFromChannels(channel);
  }

  #endregion     
 }
}
아래 와 같이 사용:

/// <summary>
/// Redis List          ,            ,     ,              ,
/// Redis       ,                   。 
///   / /        /    
/// </summary>
public static void ShowList()
{
 using (RedisListService service = new RedisListService())
 {
  service.FlushAll();
  service.AddItemToList("article", "  ");
  service.AddItemToList("article", "  ");
  service.AddItemToList("article", "  ");
  service.PrependItemToList("article", "  ");
  service.PrependItemToList("article", "  ");

  var result1 = service.GetAllItemsFromList("article"); //          
  var result2 = service.GetRangeFromList("article", 0, 3); //            ,        
  Console.WriteLine($"result1={JsonConvert.SerializeObject(result1)}");
  Console.WriteLine($"result2={JsonConvert.SerializeObject(result2)}");

  Console.WriteLine("=====================================================");

  // :    
  service.FlushAll();
  service.PushItemToList("article", "  "); //  
  service.PushItemToList("article", "  ");
  service.PushItemToList("article", "  ");
  service.PushItemToList("article", "  ");
  service.PushItemToList("article", "  ");

  for (int i = 0; i < 5; i++)
  {
   Console.WriteLine(service.PopItemFromList("article")); //  
  }

  Console.WriteLine("=====================================================");

  //  :    ,         
  //MSMQ---RabbitMQ---ZeroMQ---RedisList     、    
  service.FlushAll();
  service.EnqueueItemOnList("article", "  "); //  
  service.EnqueueItemOnList("article", "  ");
  service.EnqueueItemOnList("article", "  ");
  service.EnqueueItemOnList("article", "  ");
  service.EnqueueItemOnList("article", "  ");

  for (int i = 0; i < 5; i++)
  {
   Console.WriteLine(service.DequeueItemFromList("article")); //  
  }
  //     ,          ,     ,     ,          
 }
}
실행 결 과 는 다음 과 같다.

다음은 위의 API 를 어떻게 사용 하여 구체 적 인 문 제 를 해결 하 는 지 살 펴 보 겠 습 니 다.
1.블 로그 데이터 페이지
응용 필드:
블 로그 사이트 에 매일 새로 추 가 된 수필 과 글 은 수천 만 원 일 수 있 으 며,표 에는 수천 만 원 의 데이터 가 들 어 있다.첫 페이지 에 서 는 최신 수필 을 보 여 주 려 고 하고,20 페이지 전에는 많은 사람들 이 방문 했다.
이런 상황 에서 첫 페이지 의 페이지 데이터 가 매번 데이터 베 이 스 를 조회 하면 매우 큰 성능 문제 가 생 길 수 있다.
해결 방안:
데이터베이스 에 쓸 때마다 ID제목 은 Redis 의 List 에 기록 합 니 다.
이렇게 되면 사용자 가 페이지 를 칠 할 때마다 데이터 베 이 스 를 방문 하지 않 고 Redis 의 데 이 터 를 직접 읽 을 수 있 습 니 다.
첫 페이지(물론 앞의 몇 페이지 일 수도 있 습 니 다)는 총 기록 수 를 나타 내지 않 고 최신 데이터 로 만 보 여 줌 으로 써 데이터 베 이 스 를 방문 하 는 것 을 피 할 수 있 습 니 다.
또 하 나 는 수평 분 표 입 니 다.데이터 가 Redis 에 저 장 될 때 ID 를 저장 할 수 있 습 니 다.표 이름표제
List 를 사용 하 는 것 은 주로 데이터 양 이 많 고 변화 가 빠 른 데이터 페이지 문 제 를 해결 하 는 것 이다.
28 원칙:80%의 방문 은 20%의 데이터 에 집중 되 고 List 에 서 는 대략적인 양 만 저장 하면 충분 합 니 다.

using TianYa.Redis.Service;

namespace MyRedis.Scene
{
 /// <summary>
 ///       
 /// 
 ///     :
 ///                         ,         。          ,   20        。
 ///                        ,            。
 /// 
 ///     :
 ///            ,  ID_      Redis List (    TrimList,     200 )。
 ///                        ,    Redis    。
 ///     (         )            ,        ,            。
 /// 
 ///            ,    Redis        ID_   _  
 /// 
 ///   List         ,          。
 ///     :80%      20%   ,List              。
 /// </summary>
 public class BlogPageList
 {
  public static void Show()
  {
   using (RedisListService service = new RedisListService())
   {
    service.AddItemToList("newBlog", "10001_IOC       ");
    service.AddItemToList("newBlog", "10002_AOP      ");
    service.AddItemToList("newBlog", "10003_       ");
    service.AddItemToList("newBlog", "10004_       ");
    service.AddItemToList("newBlog", "10005_       ");
    service.AddItemToList("newBlog", "10006_GC    ");

    service.TrimList("newBlog", 0, 200); //     201 (  List      2 32  -1 )
    var result1 = service.GetRangeFromList("newBlog", 0, 9); //   
    var result2 = service.GetRangeFromList("newBlog", 10, 19); //   
    var result3 = service.GetRangeFromList("newBlog", 20, 29); //   
   }
  }
 }
}
2.생산자 소비자 모델
분산 캐 시,다 중 서버 에 접근 할 수 있 습 니 다.여러 생산자,여러 소비자,모든 제품 은 한 번 만 소 비 됩 니 다.(대기 열 사용)
그 중 하나(또는 여러 개)프로그램 이 기록 되 고,다른 하나(또는 여러 개)프로그램 이 소 비 를 읽 습 니 다.시간 순 으로 데이터 가 실 패 했 으 니 다음 에 다시 시도 할 수 있 습 니 다.
다음은 예 를 들 어 보 겠 습 니 다.

데모 에는 생산자 와 소비 자 를 모 의 하 는 콘 솔 프로그램 2 개가 추가 되 었 습 니 다.

using System;
using TianYa.Redis.Service;

namespace TianYa.Producer
{
 /// <summary>
 ///      
 /// </summary>
 class Program
 {
  static void Main(string[] args)
  {
   Console.WriteLine("        。。。");
   using (RedisListService service = new RedisListService())
   {
    Console.WriteLine("    test  ");
    for (int i = 1; i <= 20; i++)
    {
     service.EnqueueItemOnList("test", $"  test{i}");
    }

    Console.WriteLine("    task  ");
    for (int i = 1; i <= 20; i++)
    {
     service.EnqueueItemOnList("task", $"  task{i}");
    }
    Console.WriteLine("      ");

    while (true)
    {
     Console.WriteLine("************     ************");
     string testTask = Console.ReadLine();
     service.EnqueueItemOnList("test", testTask);
    }
   }
  }
 }
}

using System;
using System.Threading;
using TianYa.Redis.Service;

namespace TianYa.Consumer
{
 /// <summary>
 ///      
 /// </summary>
 class Program
 {
  static void Main(string[] args)
  {
   Console.WriteLine("        。。。");
   using (RedisListService service = new RedisListService())
   {
    while (true)
    {
     var result = service.BlockingDequeueItemFromLists(new string[] { "test", "task" }, TimeSpan.FromHours(1));
     Thread.Sleep(100);
     Console.WriteLine($"       {result.Id} {result.Item}");
    }
   }
  }
 }
}
다음은.NET Core CLI 를 사용 하여 2 개의 소비자 인 스 턴 스 와 1 개의 생산자 인 스 턴 스 를 시작 합 니 다.운영 결 과 는 다음 과 같 습 니 다.

이런 비동기 행렬 은 프로젝트 에서 어떤 가치 가 있 습 니까?

PS:이 사 무 는 매우 큰 문제 입 니 다.실제 항목 에 서 는 실제 상황 에 따라 비동기 대기 열 을 사용 할 지 여 부 를 결정 해 야 합 니 다.
3.구독 발표
게시 구독:
데 이 터 를 발표 하면 모든 구독 자 들 이 받 을 수 있 습 니 다.
관찰자,하나의 데이터 소스,여러 수신 자 는 구독 만 하면 받 을 수 있 고 여러 데이터 소스 에 의 해 공유 할 수 있 습 니 다.
관찰자 모드:위 챗 구독 번호-단체 채 팅-데이터 동기 화...
다음은 작은 데 모 를 살 펴 보 겠 습 니 다.

/// <summary>
///     
///        ,          。
///     ,     ,     ,           ,         。
///       :     ---   ---    。。。
/// </summary>
public static void ShowPublishAndSubscribe()
{
 Task.Run(() =>
 {
  using (RedisListService service = new RedisListService())
  {
   service.Subscribe("TianYa", (c, message, iRedisSubscription) =>
   {
    Console.WriteLine($"  {1}{c}:{message},Dosomething else");
    if (message.Equals("exit"))
     iRedisSubscription.UnSubscribeFromChannels("TianYa");
   });//blocking
  }
 });
 Task.Run(() =>
 {
  using (RedisListService service = new RedisListService())
  {
   service.Subscribe("TianYa", (c, message, iRedisSubscription) =>
   {
    Console.WriteLine($"  {2}{c}:{message},Dosomething else");
    if (message.Equals("exit"))
     iRedisSubscription.UnSubscribeFromChannels("TianYa");
   });//blocking
  }
 });
 Task.Run(() =>
 {
  using (RedisListService service = new RedisListService())
  {
   service.Subscribe("Twelve", (c, message, iRedisSubscription) =>
   {
    Console.WriteLine($"  {3}{c}:{message},Dosomething else");
    if (message.Equals("exit"))
     iRedisSubscription.UnSubscribeFromChannels("Twelve");
   });//blocking
  }
 });
 using (RedisListService service = new RedisListService())
 {
  Thread.Sleep(1000);
  service.Publish("TianYa", "TianYa1");
  Thread.Sleep(1000);
  service.Publish("TianYa", "TianYa2");
  Thread.Sleep(1000);
  service.Publish("TianYa", "TianYa3");

  Thread.Sleep(1000);
  service.Publish("Twelve", "Twelve1");
  Thread.Sleep(1000);
  service.Publish("Twelve", "Twelve2");
  Thread.Sleep(1000);
  service.Publish("Twelve", "Twelve3");

  Thread.Sleep(1000);
  Console.WriteLine("**********************************************");

  Thread.Sleep(1000);
  service.Publish("TianYa", "exit");
  Thread.Sleep(1000);
  service.Publish("TianYa", "TianYa6");
  Thread.Sleep(1000);
  service.Publish("TianYa", "TianYa7");
  Thread.Sleep(1000);
  service.Publish("TianYa", "TianYa8");

  Thread.Sleep(1000);
  service.Publish("Twelve", "exit");
  Thread.Sleep(1000);
  service.Publish("Twelve", "Twelve6");
  Thread.Sleep(1000);
  service.Publish("Twelve", "Twelve7");
  Thread.Sleep(1000);
  service.Publish("Twelve", "Twelve8");

  Thread.Sleep(1000);
  Console.WriteLine("  ");
 }
}
실행 결 과 는 다음 과 같다.

이로써 본 고 는 모두 소개 되 었 습 니 다.당신 에 게 깨 우 침 이 있다 고 생각 되면 좋아요 를 눌 러 주세요!!
데모 소스 코드:
링크:https://pan.baidu.com/s/1_kEMCtbf2iT5pLV7irxR5Q추출 코드:v4sr
이 글 은 블 로 거들 이 심혈 을 기울 여 작성 하여 옮 겨 실 었 습 니 다.이 원문 링크 를 유지 하 십시오.https://www.cnblogs.com/xyh9039/p/14022264.html
레 디 스 의 List 유형 에 대한 상세 한 설명 은 여기까지 입 니 다.더 많은 레 디 스 List 유형 에 관 한 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부 탁 드 리 겠 습 니 다!

좋은 웹페이지 즐겨찾기