1、背景
工作中遇到一个问题,随着业务数据量加大,订单表数据到达百万级别,直接读取数据库获取多个数据结果变得很慢,打开作业页面要9s左右。因为这个页面是常用页面,所以它的频繁查询,也间接导致其它的业务,即使表数据少,也因数据库压力大而变慢。于是同事就想到利用缓存做预加载,做一个console的程序,定时将数据库这类业务大表的数据提前加载到一个缓存数据接口(webapi) ,业务就从这个接口拿缓存。其实这已是一个类似redis的做法了。
2、缓存与redis
REDIS 是REmote DIctionary Server的意思,dictionary是我们常用来做缓存的数据类型,remote表示它是和业务分隔开的,redis是专门放这些dictionary及提供一些处理接口取缓存数据的交差并集,并且可按不同的方式将处理后的数据存储到数据库的服务;
3、redis的数据结构
redis 的作者antirez曾称其为一个数据结构服务器(data structures server),这是一个非常准确的表述,redis的所有功能就是将数据以其固有的几种结构保存,并提供给用户操作这几种结构的接口。我们可以想象我们在各种语言中的那些固有数据类型及其操作。
redis目前提供四种数据类型:string,list,set及zset(sorted set)和Hash。
-string是最简单的类型,一个key对应一个value,可赋值与获取值等。
-list是一个链表结构,主要功能是push、pop、获取一个范围的所有值等等。操作中key理解为链表的名字。
-set是集合,和我们数学中的集合概念相似,对集合的操作有添加删除元素,有对多个集合求交并差等操作。操作中key理解为集合的名字。
-zset是set的一个升级版本,他在set的基础上增加了一个顺序属性,这一属性在添加修改元素的时候可以指定,每次指定后,zset会自动重新按新的值调整顺序。可以理解了有两列的mysql表,一列存value,一列存顺序。操作中key理解为zset的名字。
-Hash数据类型允许用户用Redis存储对象类型,Hash数据类型的一个重要优点是,当你存储的数据对象只有很少几个key值时,数据存储的内存消耗会很小.
另外,作者还提供了一个非常贴心的web命令行模拟页面,供初学者试用redis,地址:
http://try.redis-db.com/
4、redis的安装
(1)服务端:简单版的,用于学习,未部署到服务器上 ,在 https://github.com/dmajkic/redis/downloads 上下载最多下载量的redis-2.4.5
解压后,得到包括以下文件
其中redis-server是服务端,在redis.conf中可配置服务端的一些端口,存储方式,备份方式之类的。
下面是redis.conf的主要配置参数的意义:
daemonize:是否以后台daemon方式运行
pidfile:pid文件位置
port:监听的端口号
timeout:请求超时时间
loglevel:log信息级别
logfile:log文件位置
databases:开启数据库的数量
save * :保存快照的频率,第一个表示多长时间,第二个*表示执行多少次写操作。在一定时间内执行一定数量的写操作时,自动保存快照。可设置多个条件。
rdbcompression:是否使用压缩
dbfilename:数据快照文件名(只是文件名,不包括目录)
dir:数据快照的保存目录(这个是目录)
appendonly:是否开启appendonlylog,开启的话每次写操作会记一条log,这会提高数据抗风险能力,但影响效率。
appendfsync:appendonlylog如何同步到磁盘(三个选项,分别是每次写都强制调用fsync、每秒启用一次fsync、不调用fsync等待系统自己同步);
(2)客户端:在.net里我们操作Redis常用的组件就是ServiceStack.Redis
参照网上别人写好的代码 ,运行起来了:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ServiceStack.Redis;
using System.Threading;
namespace RedisTutorial
{
class Program
{
static void Main(string[] args)
{
var redisClient = new RedisClient("localhost");//创建连接,配置地址与端口,默认6379
using (var cars = redisClient.As<Car>()) //创建强类型客户端
{
if (cars.GetAll().Count > 0)
cars.DeleteAll();
var dansFord = new Car
{
Id = cars.GetNextSequence(), //获取id
Title = "Dan's Ford",
Make = new Make { Name = "Ford" },
Model = new Model { Name = "Fiesta" }
};
var beccisFord = new Car
{
Id = cars.GetNextSequence(),
Title = "Becci's Ford",
Make = new Make { Name = "Ford" },
Model = new Model { Name = "Focus" }
};
var vauxhallAstra = new Car
{
Id = cars.GetNextSequence(),
Title = "Dans Vauxhall Astra",
Make = new Make { Name = "Vauxhall" },
Model = new Model { Name = "Asta" }
};
var vauxhallNova = new Car
{
Id = cars.GetNextSequence(),
Title = "Dans Vauxhall Nova",
Make = new Make { Name = "Vauxhall" },
Model = new Model { Name = "Nova" }
};
var carsToStore = new List<Car> { dansFord, beccisFord, vauxhallAstra, vauxhallNova }; //存list类型数据
cars.StoreAll(carsToStore);
Console.WriteLine("Redis Has-> " + cars.GetAll().Count + " cars");
cars.ExpireAt(vauxhallAstra.Id, DateTime.Now.AddSeconds(5)); //指定失效时间,Expire Vauxhall Astra in 5 seconds
Thread.Sleep(6000); //Wait 6 seconds to prove we can expire our old Astra
Console.WriteLine("Redis Has-> " + cars.GetAll().Count + " cars");
//Get Cars out of Redis
var carsFromRedis = cars.GetAll().Where(car => car.Make.Name == "Ford");
foreach (var car in carsFromRedis)
{
Console.WriteLine("Redis Has a ->" + car.Title);
}
}
Console.ReadLine();
}
}
public class Car
{
public long Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public Make Make { get; set; }
public Model Model { get; set; }
}
public class Make
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Model
{
public int Id { get; set; }
public Make Make { get; set; }
public string Name { get; set; }
}
}
由上可以看到,
1)redis提供了简单有用的缓存API,可简单地配置缓存的超时时间,缓存不同的C#数据类型(包括且不限于C#基础数据类型)的内容等等;
2)redis相比关系型数据库,有较强的数据处理能力的
下一篇想学习如何将redis部署到服务器,以及数据通过备份到硬盘的机制来做到持久化。