ServiceStack.Redis

初识Redis时接触到的.Net-Redis组件是 ServiceStack.Redis,其V3系列的最新版本是:ServiceStack.Redis.3.9.29.0

ServiceStack.Common.dll
ServiceStack.Interfaces.dll
ServiceStack.Redis.dll
ServiceStack.Text.dll

RedisClient

public void Init();
public bool ContainsKey(string key);
public bool Remove(string key);
public void RemoveByPattern(string pattern);
public void RemoveByRegex(string pattern);
public IEnumerable<string> GetKeysByPattern(string pattern);
public List<string> SearchKeys(string pattern);
public List<string> GetAllKeys(); // 数据库内的所有键(慎用)
public string GetRandomKey();
public T Get<T>(string key);
public IRedisTypedClient<T> As<T>(); // /* 重要 */
public bool Add<T>(string key, T value [, DateTime expiresAt]); // [设置过期时间]
public bool Add<T>(string key, T value [, TimeSpan expiresIn]);
public bool Set<T>(string key, T value [, DateTime expiresAt]); // [设置过期时间]
public bool Set<T>(string key, T value [, TimeSpan expiresIn]);
public bool ExpireEntryAt(string key, DateTime expireAt); // 设置过期时间
public bool ExpireEntryIn(string key, TimeSpan expireIn);
public TimeSpan GetTimeToLive(string key); // TTL时间
public long DecrementValue(string key); // 减
public long DecrementValueBy(string key, int count);
public long IncrementValue(string key); // 增
public long IncrementValueBy(string key, int count);

支持类型

// string
public long GetStringCount(string key);
public string GetValue(string key);
public void SetValue(string key, string value [, TimeSpan expireIn]);
public void RenameKey(string fromName, string toName);
public int AppendToValue(string key, string value);
public string GetAndSetValue(string key, string value);
public string GetSubstring(string key, int fromIndex, int toIndex);
public List<string> GetValues(List<string> keys);
public Dictionary<string, string> GetValuesMap(List<string> keys); // List
public int GetListCount(string listId);
public int RemoveItemFromList(string listId, string value);
public string RemoveStart/End/AllFromList(string listId);
public void SetItemInList(string listId, int listIndex, string value);
public void AddItemToList(string listId, string value);
public void AddRangeToList(string listId, List<string> values);
public List<string> GetAllItemsFromList(string listId);
public string GetItemFromList(string listId, int listIndex);
public List<string> GetRangeFromList(string listId, int startingFrom, int endingAt);
public List<string> GetRangeFromSortedList(string listId, int startingFrom, int endingAt);
public List<string> GetSortedItemsFromList(string listId, SortOptions sortOptions);
public List<T> GetValues<T>(List<string> keys);
public Dictionary<string, T> GetValuesMap<T>(List<string> keys);
// List作为队列
public void EnqueueItemOnList(string listId, string value);
public string DequeueItemFromList(string listId);
// List作为栈
public void PushItemToList(string listId, string value);
public string PopItemFromList(string listId);
public string PopAndPushItemBetweenLists(string fromListId, string toListId); // Set
public int GetSetCount(string setId);
public bool SetContainsItem(string setId, string item);
public void RemoveItemFromSet(string setId, string item);
public void AddItemToSet(string setId, string item);
public void AddRangeToSet(string setId, List<string> items);
public HashSet<string> GetAllItemsFromSet(string setId);
public string GetRandomItemFromSet(string setId);
public List<string> GetSortedEntryValues(string setId, int startingFrom, int endingAt);
public HashSet<string> GetDifferencesFromSet(string fromSetId, params string[] withSetIds);
public HashSet<string> GetIntersectFromSets(params string[] setIds);
public HashSet<string> GetUnionFromSets(params string[] setIds);
public void StoreDifferencesFromSet(string intoSetId, string fromSetId, params string[] withSetIds);
public void StoreIntersectFromSets(string intoSetId, params string[] setIds);
public void StoreUnionFromSets(string intoSetId, params string[] setIds);
public void MoveBetweenSets(string fromSetId, string toSetId, string item);
public string PopItemFromSet(string setId);  // Hash
public int GetHashCount(string hashId);
public bool HashContainsEntry(string hashId, string key);
public bool RemoveEntryFromHash(string hashId, string key);
public bool SetEntryInHash(string hashId, string key, string value);
public List<string> GetHashKeys(string hashId);
public List<string> GetHashValues(string hashId);
public Dictionary<string, string> GetAllEntriesFromHash(string hashId);
public string GetValueFromHash(string hashId, string key);
public List<string> GetValuesFromHash(string hashId, params string[] keys);
public T GetFromHash<T>(object id); // SortedSet(zset)
public int GetSortedSetCount(string setId);
public bool SortedSetContainsItem(string setId, string value);
public bool RemoveItemFromSortedSet(string setId, string value);
public bool AddItemToSortedSet(string setId, string value [, double score]);
public bool AddRangeToSortedSet(string setId, List<string> values [, double score]);
public List<string> GetRangeFromSortedSet(string setId, int fromRank, int toRank);
public IDictionary<string, double> GetRangeWithScoresFromSortedSet(string setId, int fromRank, int toRank);
public List<string> GetAllItemsFromSortedSet[Desc](string setId);
public IDictionary<string, double> GetAllWithScoresFromSortedSet(string setId);

其中, public IRedisTypedClient<T> As<T>();  搭配接口 public interface IRedisTypedClient<T> : IEntityStore<T>{} 和 public interface IEntityStore<T>{}  中提供的方法可以完成各种操作。

在V3.0版本的基础上,其V4.0版本 ServiceStack.Redis-4.0.52 提供了更多的方法:

  • Scan方法;
  • 获取设置配置信息;
  • 支持Lua脚本; 
public RedisText Custom(params object[] cmdWithArgs);  // 执行命令
public RedisClient CloneClient();
public string GetClient();
public void SetClient(string name);
public void KillClient(string address);
public void ChangeDb(long db);
public DateTime GetServerTime();
public DateTime ConvertToServerDate(DateTime expiresAt);
public List<Dictionary<string, string>> GetClientsInfo();
public string GetConfig(string configItem);
public void SetConfig(string configItem, string value);
public void SaveConfig();
public void ResetInfoStats();

其中,Custom()方法可以执行绝大多数的Redis命令,ServiceStack.Redis.Commands定义命令,用于Custom()方法的第一个参数:

public static class Commands{
public static readonly byte[] CommandName;
}

由于ServiceStack.Redis的V4.0版本沦为商业用途,需充值否则限制:1)数据类型; 2)每小时访问次数6000

关于破解V4.0版本限制,参见:https://blog.csdn.net/hwt0101/article/details/80545383

虽然ServiceStack.Redis有15%的性能优势,但还是推荐使用:StackExchange.Redis 

StackExchange.Redis

StackExchange.Redis是专为.Net的Redis客户端API,被StackOverFlow、微软官方RedisSessionStateProvider也采用StackExchange.Redis实现。Cache组件 | 微软官方

RedisHelper.dll
StackExchange.Redis.dll

核心:ConnectionMultiplexer类(线程安全),在命名空间StackExchange.Redis中定义,封装Redis服务的操作细节,该类的实例被整个应用程序域共享和重用

ConnectionMultiplexer redisClient = ConnectionMultiplexer.Connect("localhost");
IDatabase db = redisClient .GetDatabase();

提供一个工具类参考

public class RedisUtils<T> where T : class
{
private readonly ConnectionMultiplexer redisConnect;
private readonly IDatabase db;
private readonly JilJsonUtil<T> _jilUtil; public RedisUtils(string connectionString)
{
_jilUtil = new JilJsonUtil<T>();
redisConnect = ConnectionMultiplexer.Connect(connectionString);
redisConnect.PreserveAsyncOrder = false;
db = redisConnect.GetDatabase();
} public string GetString(string _key)
{
return db.StringGet(_key);
}
public Dictionary<String, T> GetBatch(HashSet<String> keys)
{
Dictionary<String, T> res = new Dictionary<String, T>(); Dictionary<string, RedisValue> stringPipelineDic= GetStringPipelining(keys);
foreach (var key in stringPipelineDic.Keys)
{
var value = stringPipelineDic[key];
if (!value.IsNullOrEmpty)
{
res.Add(key, _jilUtil.Deserialize(value));
}
} return res;
} ///批量查询
private Dictionary<string, RedisValue> GetStringPipelining(HashSet<String> keys)
{
Dictionary<string, RedisValue> res = new Dictionary<string, RedisValue>(); Dictionary<string, Task<RedisValue>> tmp = new Dictionary<string, Task<RedisValue>>();
IBatch batch = db.CreateBatch();
foreach (var it in keys)
{
Task<RedisValue> stringGetAsync = batch.StringGetAsync(it);
tmp.Add(it, stringGetAsync);
}
batch.Execute(); foreach (var it in keys)
{
Task<RedisValue> stringGetAsync = tmp[it];
if (!stringGetAsync.Result.IsNullOrEmpty)
{
res.Add(it, stringGetAsync.Result);
}
} return res;
} ///存单个string的最大值是512M
public bool SetString(string key, string valStr, int seconds)
{
return db.StringSet(key, valStr, TimeSpan.FromSeconds(seconds));
}
public bool Set(string key, T value, int seconds)
{
var jsonStr = _jilUtil.Serialize(value);
return db.StringSet(key, jsonStr, TimeSpan.FromSeconds(seconds));
} ///PipeLine
public void SetBatch(Dictionary<string, T> dic, int seconds)
{
IBatch ibatch = db.CreateBatch();
foreach (var _key in dic.Keys)
{
T val = dic[_key];
ibatch.StringSetAsync(_key, _jilUtil.Serialize(val), TimeSpan.FromSeconds(seconds));
}
ibatch.Execute();
}
}

问题解决

[1]. 连接redis集群报错:(StackExchange.Redis.dll-v1.2.1)

StackExchange.Redis.RedisConnectionException: It was not possible to connect to the redis server(s);
to create a disconnected multiplexer, disable AbortOnConnectFail. InternalFailure on PING
在 StackExchange.Redis.ConnectionMultiplexer.ConnectImpl(Func`1 multiplexerFactory, TextWriter log)
在 StackExchange.Redis.ConnectionMultiplexer.Connect(String configuration, TextWriter log)

原因:客户端dll版本与redis集群不兼容,替换为 v1.2.6 即可

管道(PipeLine)/批量(Batch)

  • 命令打包,降低通信往返时延

关于性能提升:参考1参考2

StackExchange.Redis两个神器:ConnectionCounters 和 IProfiler

  • ConnectionCounters:分析线程瞬时状态
  • IProfiler:跟踪一个请求总共执行redis命令及执行时长

对StackExchange.Redis的封装,参见:

但是,V1.0版本存在 timeout的问题,超时和异步慢的问题初探解决方法:

// 解决超时
ThreadPool.SetMinThreads(xx, xx);
// 解决异步慢
connection.PreserveAsyncOrder = false;

该问题在 StackExchange.Redis 2.0 中已解决,重构了异步队列,采用管道方式解决了异步慢的问题,参见:https://www.cnblogs.com/qhca/p/9347604.html

StackExchange.Redis二次封装 中,建议不要用lock作为单例使用,避免出现超时问题,待验证....

应用

Log4net+redis日志队列:https://www.cnblogs.com/dissun/p/10558817.html

Redis监控:由 Opserver工具  ==> RedisMonitor

基于 Redis的 Session共享

环境配置

.NET Framework 4.5 (推荐配置)
Microsoft.Web.RedisSessionStateProvider V2.2.6
StackExchange.Redis.StrongName V1.2.1 .NET Framework 4.6.1
RedisSessionProvider V1.2.8
StackExchange.Redis V2.0.6(貌似会报错,提示用低版本V1.2.6)

使用方法  

public static void RegistRedis()
{
StackExchange.Redis.ConfigurationOptions redisConfigOpts =
StackExchange.Redis.ConfigurationOptions.Parse("127.0.0.1:6379");
redisConfigOpts.Password = "********"; RedisSessionProvider.Config.RedisConnectionConfig.GetSERedisServerConfig =
(context) =>
{
return new KeyValuePair<string, StackExchange.Redis.ConfigurationOptions>(
"DefaultConnection", redisConfigOpts);
};
RedisSessionProvider.Config.RedisSessionConfig.SessionTimeout = TimeSpan.MaxValue;
}

CsRedis.Core

CsRedis 开源地址参见:https://github.com/2881099/csredis

/// .NET Framework 4.6
/// NuGet.Tools.vsix V2.12
/// CSRdeis.Core V3.0.62

CsRedis引入:https://www.cnblogs.com/kellynic/p/9803314.html

最新文章

  1. centos 7.0 安装nginx 1.9.10
  2. 安装mysql步骤
  3. 考查SQLite 3索引对整数排序的性能影响
  4. 用Jenkins配置自动化构建
  5. 关于 iOS 批量打包的总结
  6. Leveldb 实现原理
  7. out ref区别
  8. nginx编译
  9. HDU 5961 传递 【图论+拓扑】 (2016年中国大学生程序设计竞赛(合肥))
  10. Python高级之Socket 探索(五)
  11. (step7.2.4)hdu 2674(N!Again——简单数论)
  12. LDA和PCA
  13. MVC加载分布页的三种方式
  14. 【Android基础】利用Intent在Activity之间传递数据
  15. 值得关注的10个python语言博客
  16. JS--操作DOM树
  17. C# List 作为参数传递的值变化
  18. OkHttp踩坑记:为何 response.body().string() 只能调用一次?
  19. 【Python】数据库练习-2
  20. kafka----&gt;kafka的使用(一)

热门文章

  1. 【Mac】解决外接显示器时无法用键盘调节音量
  2. linux追加所有文件到新的文件(cat)
  3. 一个80后妈妈的邪淫忏悔(转自学佛网:http://www.xuefo.net/nr/article55/551761.html)
  4. C#多线程编程实例 线程与窗体交互
  5. 【Leetcode_easy】942. DI String Match
  6. python3传文件到linux服务器然后解压
  7. curl --resolve 查看证书情况
  8. 【GStreamer开发】GStreamer播放教程03——pipeline的快捷访问
  9. vue 跨域简记
  10. WXS --注释