Skip to content

Commit

Permalink
Redis基础文档
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Sep 25, 2018
1 parent b723e88 commit 0909046
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 22 deletions.
147 changes: 147 additions & 0 deletions NewLife.Core/Caching/Readme.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
缓存架构以ICache接口为核心,包括MemoryCache、Redis和DbCache实现!
后续例程与使用说明均以Redis为例,各缓存实现类似。

### 内存缓存 MemoryCache
MemoryCache核心是并行字典ConcurrentDictionary,由于省去了序列化和网络通信,使得它具有千万级超高性能。
MemoryCache支持过期时间,默认容量10万个,未过期key超过该值后,每60秒根据LRU清理溢出部分。
常用于进程内千万级以下数据缓存场景。

```csharp
// 缓存默认实现Cache.Default是MemoryCache,可修改
//var ic = Cache.Default;
//var ic = new MemoryCache();
```

### 基础 Redis
Redis实现标准协议以及基础字符串操作,完整实现由独立开源项目[NewLife.Redis](https://github.com/NewLifeX/NewLife.Redis)提供。
采取连接池加同步阻塞架构,具有超低延迟(200~600us)以及超高吞吐量的特点。
在物流行业大数据实时计算中广泛应有,经过日均100亿次调用量验证。

```csharp
// 实例化Redis,默认端口6379可以省略,密码有两种写法
//var ic = Redis.Create("127.0.0.1", 7);
var ic = Redis.Create("[email protected]:6379", 7);
//var ic = Redis.Create("server=127.0.0.1:6379;password=pass", 7);
ic.Log = XTrace.Log; // 调试日志。正式使用时注释
```

### 数据库 DbCache
DbCache属于实验性质,采用数据库存储数据,默认SQLite。

### 基本操作
在基本操作之前,我们先做一些准备工作:
+ 新建控制台项目,并在入口函数开头加上 `XTrace.UseConsole();` ,这是为了方便查看调试日志
+ 具体测试代码之前,需要加上前面MemoryCache或Redis的实例化代码
+ 准备一个模型类User
```csharp
class User
{
public String Name { get; set; }
public DateTime CreateTime { get; set; }
}
```

添删改查:
```csharp
var user = new User { Name = "NewLife", CreateTime = DateTime.Now };
ic.Set("user", user, 3600);
var user2 = ic.Get<User>("user");
XTrace.WriteLine("Json: {0}", ic.Get<String>("user"));
if (ic.ContainsKey("user")) XTrace.WriteLine("存在!");
ic.Remove("user");
```

执行结果:
```csharp
14:14:25.990 1 N - SELECT 7
14:14:25.992 1 N - => OK
14:14:26.008 1 N - SETEX user 3600 [53]
14:14:26.021 1 N - => OK
14:14:26.042 1 N - GET user
14:14:26.048 1 N - => [53]
14:14:26.064 1 N - GET user
14:14:26.065 1 N - => [53]
14:14:26.066 1 N - Json: {"Name":"NewLife","CreateTime":"2018-09-25 14:14:25"}
14:14:26.067 1 N - EXISTS user
14:14:26.068 1 N - => 1
14:14:26.068 1 N - 存在!
14:14:26.069 1 N - DEL user
14:14:26.070 1 N - => 1
```

保存复杂对象时,默认采用Json序列化,所以上面可以按字符串把结果取回来,发现正是Json字符串。
Redis的strings,实质上就是带有长度前缀的二进制数据,[53]表示一段53字节长度的二进制数据。

### 集合操作
GetAll/SetAll 在Redis上是很常用的批量操作,同时获取或设置多个key,一般有10倍以上吞吐量。

批量操作:
```csharp
var dic = new Dictionary<String, Object>
{
["name"] = "NewLife",
["time"] = DateTime.Now,
["count"] = 1234
};
ic.SetAll(dic, 120);

var vs = ic.GetAll<String>(dic.Keys);
XTrace.WriteLine(vs.Join(",", e => $"{e.Key}={e.Value}"));
```

执行结果:
```csharp
MSET name NewLife time 2018-09-25 15:56:26 count 1234
=> OK
EXPIRE name 120
EXPIRE time 120
EXPIRE count 120
MGET name time count
name=NewLife,time=2018-09-25 15:56:26,count=1234
```

集合操作里面还有 `GetList/GetDictionary/GetQueue/GetSet` 四个类型集合,分别代表Redis的列表、哈希、队列、Set集合等。
基础版Redis不支持这四个集合,完整版[NewLife.Redis](https://github.com/NewLifeX/NewLife.Redis)支持,MemoryCache则直接支持。
### 高级操作
+ Add 添加,当key不存在时添加,已存在时返回false
+ Replace 替换,替换已有值为新值,返回旧值。
+ Increment 累加,原子操作
+ Decrement 递减,原子操作

高级操作:
```csharp
var flag = ic.Add("count", 5678);
XTrace.WriteLine(flag ? "Add成功" : "Add失败");
var ori = ic.Replace("count", 777);
var count = ic.Get<Int32>("count");
XTrace.WriteLine("count由{0}替换为{1}", ori, count);

ic.Increment("count", 11);
var count2 = ic.Decrement("count", 10);
XTrace.WriteLine("count={0}", count2);
```

执行结果:
```csharp
SETNX count 5678
=> 0
Add失败
GETSET count 777
=> 1234
GET count
=> 777
count1234替换为777
INCRBY count 11
=> 788
DECRBY count 10
=> 778
count=778
```

### 性能测试
Bench 会分根据线程数分多组进行添删改压力测试。
rand 参数,是否随机产生key/value
batch 批大小,分批执行读写操作,借助GetAll/SetAll进行优化。

Redis默认设置AutoPipeline=100,无分批时打开管道操作,对添删改优化。
1 change: 1 addition & 0 deletions NewLife.Core/NewLife.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@
<DependentUpon>SerialPortList.cs</DependentUpon>
</EmbeddedResource>
<Compile Include="Extension\EndPointExtensions.cs" />
<None Include="Caching\Readme.MD" />
<None Include="Log\Readme.md" />
<None Include="Net\Readme.md" />
<None Include="Remoting\ApiClient.cd" />
Expand Down
66 changes: 44 additions & 22 deletions Test/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using NewLife.Remoting;
using NewLife.Security;
using NewLife.Serialization;
using NewLife.Threading;
using XCode.DataAccessLayer;
using XCode.Membership;
using XCode.Service;
Expand Down Expand Up @@ -138,24 +137,6 @@ static void Test2()
Console.WriteLine(gs.First().Logins);
}

class CacheItem<TValue>
{
/// <summary>数值</summary>
public TValue Value { get; set; }

/// <summary>过期时间</summary>
public DateTime ExpiredTime { get; set; }

/// <summary>是否过期</summary>
public Boolean Expired => ExpiredTime <= TimerX.Now;

public CacheItem(TValue value, Int32 seconds)
{
Value = value;
if (seconds > 0) ExpiredTime = TimerX.Now.AddSeconds(seconds);
}
}

static void Test3()
{
var svr = new ApiServer(3344)
Expand Down Expand Up @@ -295,10 +276,51 @@ static void Test5()

static void Test6()
{
var rds = Redis.Create("127.0.0.1", 7);
// 缓存默认实现Cache.Default是MemoryCache,可修改
//var ic = Cache.Default;
//var ic = new MemoryCache();

// 实例化Redis,默认端口6379可以省略,密码有两种写法
var ic = Redis.Create("127.0.0.1", 7);
//var ic = Redis.Create("[email protected]:6379", 7);
//var ic = Redis.Create("server=127.0.0.1:6379;password=pass", 7);
ic.Log = XTrace.Log; // 调试日志。正式使用时注释

var user = new User { Name = "NewLife", CreateTime = DateTime.Now };
ic.Set("user", user, 3600);
var user2 = ic.Get<User>("user");
XTrace.WriteLine("Json: {0}", ic.Get<String>("user"));
if (ic.ContainsKey("user")) XTrace.WriteLine("存在!");
ic.Remove("user");

var dic = new Dictionary<String, Object>
{
["name"] = "NewLife",
["time"] = DateTime.Now,
["count"] = 1234
};
ic.SetAll(dic, 120);

var vs = ic.GetAll<String>(dic.Keys);
XTrace.WriteLine(vs.Join(",", e => $"{e.Key}={e.Value}"));

var flag = ic.Add("count", 5678);
XTrace.WriteLine(flag ? "Add成功" : "Add失败");
var ori = ic.Replace("count", 777);
var count = ic.Get<Int32>("count");
XTrace.WriteLine("count由{0}替换为{1}", ori, count);

//rds.AutoPipeline = 1000;
rds.Bench();
ic.Increment("count", 11);
var count2 = ic.Decrement("count", 10);
XTrace.WriteLine("count={0}", count2);

//ic.Bench();
}

class User
{
public String Name { get; set; }
public DateTime CreateTime { get; set; }
}

static void Test7()
Expand Down

0 comments on commit 0909046

Please sign in to comment.