Redis安装
Redis是一个用的比较广泛的Key/Value的内存数据库。目前新浪微博、Github、StackOverflow 等大型应用中都用其作为缓存,和Memcached类似,但是支持数据的持久化,解决了断电后数据完全丢失的情况。而且它支持更多的类型,除了string外,还支持lists(链表)、sets(集合)和zsets(有序集合)几种数据类型。
下载地址:
http://redis.io/download
Redis安装
Redis的安装非常的简单,而且Redis并不依赖其他环境和标准库,很容易上手,这可能也是它流行的一个原因。这里为了测试方便,用的都是windows 环境下测试。
- redis.windows.conf 是redis的配置文件。
- redis-server.exe 服务器端。
- redis-cli.exe 命令行客户端。
- redis-benchmark.exe Redis性能测试工具,测试Redis在你的系统及你的配置下的读写性能。
启动服务
在命令行输入如下命令 :redis-server redis.windows.conf。
同时也可以该命令保存为文件 startup.bat,下次就可以直接启动了。
如果提示redis-server 不是内部命令。将该目录加到环境变量里面即可。
redis相关配置
1. port 端口号,例如6379
port 6379
2. bind 实例绑定的访问地址127.0.0.1
bind 127.0.0.1
3. requirepass 访问的密码
requirepass 456
4. maxheap 记得把这个配置节点打开,否者redis 服务无法启动。例如maxheap 1024000000
maxheap 1024000000
5. timeout:请求超时时间
timeout 300
6. logfile:log文件位置
logfile stdout
7. databases:开启数据库的数量
databases 16
8. dbfilename:数据快照文件名(只是文件名,不包括目录)
dbfilename dump.rdb
连接测试
在命令行输入如下命令:
redis-cli -h 127.0.0.1 -p 6379 -a 456
参数分别为host、port,如果设置了密码,则必须要加上-a 456,456为登录密码。否则会提示没有权限登录系统。
如下图所示。
读写分离配置
redis的读写分离需要修改配置文件,把解压的文件复制了一份。两份文件是一样的,分别命名为MasterRedis-2.8.19(主redis服务),SlaveRedis-2.8.19(从redis服务)。redis默认绑定的是6379端口,
我们保持主服务配置不变,修改从服务配置。
- 修改从服务绑定端口(修改时可以直接搜索port关键字)
port 6380
- 修改从服务对应的主服务地址(修改时可以直接搜索slaveof关键字)
slaveof 127.0.0.1 6379
- 配置文件修改完成以后,分别启动主服务和从服务
配置好我们看下redis的日志 看是否同步成功
5014:S 25 Jan 10:53:53.667 * Connecting to MASTER 221.224.85.186:6379
5014:S 25 Jan 10:53:53.667 * MASTER <-> SLAVE sync started
5014:S 25 Jan 10:53:53.700 * Non blocking connect for SYNC fired the event.
5014:S 25 Jan 10:53:53.734 * Master replied to PING, replication can continue...
5014:S 25 Jan 10:53:53.832 * Partial resynchronization not possible (no cached master)
5014:S 25 Jan 10:53:53.867 * Full resync from master: 4d6221e370675f397c396c9222b1b60bfcea1efb:1
5014:S 25 Jan 10:53:53.985 * MASTER <-> SLAVE sync: receiving 844 bytes from master
5014:S 25 Jan 10:53:53.985 * MASTER <-> SLAVE sync: Flushing old data
5014:S 25 Jan 10:53:53.985 * MASTER <-> SLAVE sync: Loading DB in memory
5014:S 25 Jan 10:53:53.985 * MASTER <-> SLAVE sync: Finished with success
五种数据类型使用
服务搭建好以后可以使用.Net版本Redis操作类库ServiceStack.Redis
String
String是最常用的一种数据类型,普通的key/value存储都可以归为此类,value其实不仅是String,也可以是数字:比如想知道什么时候封锁一个IP地址(访问超过几次)。INCRBY命令让这些变得很容易,通过原子递增保持计数。
var client = new RedisClient("127.0.0.1", 6379);
client.Set<string>("name", "Bobby");
string userName = client.Get<string>("name");
Console.WriteLine(userName);
// 访问次数
client.Set<int>("IpAccessCount", 0);
// 次数递增
client.Incr("IpAccessCount");
Console.WriteLine(client.Get<int>("IpAccessCount"));
Console.Read();
Bobby
1
Hash
一个hashid可以存储多项信息,每一项信息也有自己的key。
var client = new RedisClient("127.0.0.1", 6379);
client.SetEntryInHash("userInfoId", "name", "zhangsan");
client.SetEntryInHash("userInfoId", "name1", "zhangsan1");
client.SetEntryInHash("userInfoId", "name2", "zhangsan2");
client.SetEntryInHash("userInfoId", "name3", "zhangsan3");
client.GetHashKeys("userInfoId").ForEach(e => Console.WriteLine(e));
client.GetHashValues("userInfoId").ForEach(e => Console.WriteLine(e));
Console.Read();
name
name1
name2
name3
zhangsan
zhangsan1
zhangsan2
zhangsan3
List
应用场景:
- Redis list的应用场景非常多,也是Redis最重要的数据结构之一。
- 我们可以轻松地实现最新消息排行等功能。
- Lists的另一个应用就是消息队列,可以利用Lists的PUSH操作,将任务存在Lists中,然后工作线程再用POP操作将任务取出进行执行。
var client = new RedisClient("127.0.0.1", 6379);
#region List类型
client.AddItemToList("userInfoId1", "张三");
client.AddItemToList("userInfoId1", "李四");
Console.WriteLine("List数据项条数:" + client.GetListCount("userInfoId1"));
Console.WriteLine("List数据项第一条数据:" + client.GetItemFromList("userInfoId1", 0));
Console.WriteLine("List所有数据");
client.GetAllItemsFromList("userInfoId1").ForEach(e => Console.WriteLine(e));
#endregion
Console.WriteLine(client.GetListCount("userInfoId1"));
// 队列先进先出
//Console.WriteLine(client.DequeueItemFromList("userInfoId1"));
//Console.WriteLine(client.DequeueItemFromList("userInfoId1"));
// 栈后进先出
Console.WriteLine("出栈" + client.PopItemFromList("userInfoId1"));
Console.WriteLine("出栈" + client.PopItemFromList("userInfoId1"));
Console.Read();
List数据项条数:2
List数据项第一条数据:张三
List所有数据
张三
李四
2 栈后进先出
出栈李四
出栈张三
Set
应用场景:
- Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
- 比如在微博应用中,每个人的好友存在一个集合(set)中,这样求两个人的共同好友的操作,可能就只需要用求交集命令即可。
- Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实
var client = new RedisClient("127.0.0.1", 6379);
client.AddItemToSet("A", "B");
client.AddItemToSet("A", "C");
client.AddItemToSet("A", "D");
client.AddItemToSet("A", "E");
client.AddItemToSet("A", "F");
client.AddItemToSet("B", "C");
client.AddItemToSet("B", "F");
// 求差集
Console.WriteLine("A,B集合差集");
client.GetDifferencesFromSet("A", "B").ToList<string>().ForEach(e => Console.Write(e + ","));
// 求集合交集
Console.WriteLine("\nA,B集合交集");
client.GetIntersectFromSets(new string[] { "A", "B" }).ToList<string>().ForEach(e => Console.Write(e + ","));
// 求集合并集
Console.WriteLine("\nA,B集合并集");
client.GetUnionFromSets(new string[] { "A", "B" }).ToList<string>().ForEach(e => Console.Write(e + ","));
Console.Read();
A,B集合差集
B,D,E,
A,B集合交集
F,C,
A,B集合并集
C,B,F,D,E,
Sort Set(排序)
应用场景:
- 以某个条件为权重,比如按顶的次数排序.
- ZREVRANGE命令可以用来按照得分来获取前100名的用户,ZRANK可以用来获取用户排名,非常直接而且操作容易。
- Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。
- 比如:twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。
- 比如:全班同学成绩的SortedSets,value可以是同学的学号,而score就可以是其考试得分,这样数据插入集合的,就已经进行了天然的排序。
- 另外还可以用Sorted Sets来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。
var client = new RedisClient("127.0.0.1", 6379);
#region "有序Set操作"
client.AddItemToSortedSet("SA", "B", 2);
client.AddItemToSortedSet("SA", "C", 1);
client.AddItemToSortedSet("SA", "D", 5);
client.AddItemToSortedSet("SA", "E", 3);
client.AddItemToSortedSet("SA", "F", 4);
// 有序集合降序排列
Console.WriteLine("\n有序集合降序排列");
client.GetAllItemsFromSortedSetDesc("SA").ForEach(e => Console.Write(e + ","));
Console.WriteLine("\n有序集合升序序排列");
client.GetAllItemsFromSortedSet("SA").ForEach(e => Console.Write(e + ","));
client.AddItemToSortedSet("SB", "C", 2);
client.AddItemToSortedSet("SB", "F", 1);
client.AddItemToSortedSet("SB", "D", 3);
Console.WriteLine("\n获得某个值在有序集合中的排名,按分数的升序排列");
Console.WriteLine(client.GetItemIndexInSortedSet("SB", "D"));
Console.WriteLine("\n获得有序集合中某个值得分数");
Console.WriteLine(client.GetItemScoreInSortedSet("SB", "D"));
Console.WriteLine("\n获得有序集合中,某个排名范围的所有值");
client.GetRangeFromSortedSet("SA", 0, 3).ForEach(e => Console.Write(e + ","));
#endregion
Console.Read();
有序集合降序排列
D,F,E,B,C,
有序集合升序序排列
C,B,E,F,D,
获得某个值在有序集合中的排名,按分数的升序排列
2
获得有序集合中某个值得分数
3
获得有序集合中,某个排名范围的所有值
C,B,E,F,
Redis操作的帮助类库 Tdf.RedisCache
Tdf.RedisCache,用到了PooledRedisClientManager连接池来获取RedisClient,同时用到了读写分离的概念,可以直接拿来使用。
使用很简单,几行代码
using System;
using Tdf.RedisCache;
namespace Tdf.RedisCacheTest
{
class Program
{
static void Main(string[] args)
{
RedisBase.Hash_Set<string>("PooledRedisClientManager", "UserId", "6A671BD3-8A5B-4E04-B88E-C9A1A64214A6");
RedisBase.Hash_Set<string>("PooledRedisClientManager", "UserName", "Bobby");
var userId = RedisBase.Hash_Get<string>("PooledRedisClientManager", "UserId");
var userName = RedisBase.Hash_Get<string>("PooledRedisClientManager", "UserName");
Console.WriteLine(userId + "," + userName);
Console.Read();
}
}
}
配置文件
<appSettings>
<!--Redis写入服务器地址,可以添加多个服务器通过;分隔-->
<add key="readWriteHosts" value="127.0.0.1:6379" />
<!--Redis读服务器地址,可以添加多个服务器通过;分隔-->
<add key="readOnlyHosts" value="127.0.0.1:6380" />
</appSettings>
可以使用redis desktop manager管理工具查看服务器缓存中的数据
Sentinel 哨兵
Sentinel(哨兵)是Redis 的高可用性解决方案:由一个或多个Sentinel 实例 组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。
例如:
在Server1 掉线后:
升级Server2 为新的主服务器:
Sentinel的作用:
- Master 状态监测;
- 如果Master 异常,则会进行Master-slave 转换,将其中一个Slave作为Master,将之前的Master作为Slave;
- Master-Slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生改变,即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换。
Sentinel的工作方式:
- 每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令;
- 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线;
- 如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态;
- 当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线;
- 在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令
- 当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次
- 若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除;若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。
缓存系统的三大问题
- 缓存穿透 Cache Penetration: 缓存设立的目的是为了一定层面上截获到数据库存储层的请求。穿透的意思就在于这个截获没有成功,请求最终还是去到了数据库,缓存没有产生应有的价值。
- 缓存击穿 Hotspot Invalid: 如果把缓存理解成一面挡在数据库面前的墙壁,为数据库“抵御”查询请求,所谓击穿,就是在这面墙壁上打出了一个洞。一般发生在某个热点数据缓存到期,而此时针对该数据的大量查询请求来临,大家一股脑的怼到了数据库。
- 缓存雪崩 Cache Avalanche: 理解了击穿,那雪崩就更好理解了。俗话说得好,击穿是一个人的雪崩,雪崩是一群人的击穿。如果缓存这堵墙上处处都是洞,那这面墙还如何屹立?
windows系统配置redis密码
设置密码,修改配置文件redis.windows.conf,其中123456是设置的密码
requirepass 123456 //此处注意,行前不能有空格
启动redis服务,双击redis-server.exe或者在redis文件夹下运行
redis-server.exe redis.windows.conf
重新登录获取操作权限
redis-cli.exe -h 127.0.0.1 -p 6379 -a 123456 //需添加密码参数
config get requirepass
redis使用IP地址访问
找到redis.windows.conf配置文件
- 将protected-mode 参数改为no。
- 注释掉bind 127.0.0.1
- 重启redis服务