Redis
https://github.com/MSOpenTech/redis/releases
最新的redis下载,只有64位的,微软开发的
Redis 是什么?全称:REmote DIctionary Server 远程字典服务器
基于内存管理(数据存在内存),实现了5种数据结构(分别应对各种具体需求),单线程模型的应用程序(单进程单线程),对外提供插入-查询-固化-集群功能
redis-server.exe 服务端
redis-cli.exe 客户端
redis-desktop-manager 可视化的管理工具
常见命令:
set zwk 123
get zwk 123
select 1 切换库
...
配置文件 .conf
redis服务启动时默认会加载安装根目录下的redis.conf文件来完成redis服务实例的相关配置,通常一个reids服务实例对应一个配置文件,若要在同一台服务器上启动多个redis服务实例,就必须在安装根目录下创建多个配置文件。由于每个redis服务实例都必须对应唯一的端口号,通常将对应的配置文件命名为redis_port.conf。
save 60 10000 //60s 内10000次更改
- timeout:请求超时时间
- loglevel:log信息级别
- logfile:log文件位置
- databases:开启数据库的数量
- save * *:保存快照的频率,第一个*表示多长时间,第三个*表示执行多少次写操作。在一定时间内执行一定数量的写操作时,自动保存快照。可设置多个条件。
- rdbcompression:是否使用压缩
- dbfilename:数据快照文件名(只是文件名,不包括目录)
- dir:数据快照的保存目录(这个是目录)
- appendonly:是否开启appendonlylog,开启的话每次写操作会记一条log,这会提高数据抗风险能力,但影响效率。
- appendfsync:appendonlylog如何同步到磁盘(三个选项,分别是每次写都强制调用fsync、每秒启用一次fsync、不调用fsync等待系统自己同步)
- port:配置服务的端口号,默认6379,同一服务器上启动多个服务必须在对应配置文件内指定不同端口号。
- timeout:配置客户端连接超时时间,单位秒,若客户端在规定时间内没发请求会关闭该连接,默认0无限制。
- bind:配置服务只接受来自指定ip的请求,默认127.0.0.1只接收本机请求。
- daemonize:配置服务是否为后台运行,默认no非后台运行,如需后台运行改为yes。
- pidfile:配置pid文件地址,默认/var/run/redis_6379.pid,其存储了当前服务的进程号,同一服务器上多个服务必须创建对应的多个pid文件,文件名以端口号区分。
loglevel:配置数据库日志级别,共四个级别,默认notice正常记录,debug记录全部信息,varbose仅记录有用信息,waring记录非常重要的信息。
logfile:配置数据库日志文件地址,stdout标准输出到终端显示,后台模式输出到/dev/null,null是一串口设备的文件,/export/Logs/redis/redis_6379.log输出到文件,前提必须先建立此目录及文件。
databases:配置可用数据库个数,默认16。redis没有表概念,其数据库用一个从0开始的整数索引来标识,使用select dbid来指定数据库,默认0数据库,不同数据库内key可重复。flushdb清除当前数据库内容,flushall清除当前服务所有数据库内容,dbsize返回当前数据库内k个数。
save:配置内存数据与硬盘数据库同步频率,如save
900 1,表示900秒内有一个及以上的key发生变化,就将内存数据同步到硬盘。redis有rdb和aof两种实现内存数据持久化的方式,其中rdb速度快,但会缺失数据;aof速度慢,但会完全恢复。
rdbcompression:配置内存数据同步到rdb时是否压缩数据,默认yes。
dbfilename:配置rdb数据库文件名,默认为dump.rdb,仅指出文件名。
dir:配置rdb数据库文件存放目录,默认redis安装根目录。只能指定目录,不能指定rdb文件名。
slaveof:配置当前服务的主redis服务,redis的多个服务可实现主从同步,若当前服务为从库,要在此指定主库的ip和端口,如slaveof ip port,当从库开启时,会自动从主库同步数据。
masterauth:配置从库访问主库的密码,若当前服务为从库,且要同步的主库设置了密码,要在此指定连接到主库的密码。
appendonly:配置是否开启aof持久化功能,默认no,若开启会创建xxx.aof文件,其会记录服务的每一次写操作。
appendfilename:配置aof文件的名称,默认为appendonly.aof。
appendfsync:配置服务对aof文件的同步频率,always表示一有写操作就同步,everysec表示每秒进行一次同步。
requirepass:配置客户端连接到服务的密码,默认注释掉不设置密码,此时redis进入保护模式,除了本地客户端外,远程客户端均无法连接服务。在此设置密码后可实现远程连接,但远程登录后必须执行auth password命令输入密码才可操作。
maxclients:配置服务的最大客户端连接数,默认注释掉,不加限制。
maxmemory:配置服务的最大内存,默认注释掉,不加限制。
安装
数据存储
redis的存储分为内存存储、磁盘存储和log文件三部分,配置文件中有三个参数对其进行配置。
save seconds updates,save配置,指出在多长时间内,有多少次更新操作,就将数据同步到数据文件。这个可以多个条件配合,比如默认配置文件中的设置,就设置了三个条件。
appendonly yes/no ,appendonly配置,指出是否在每次更新操作后进行日志记录,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面的save条件来同步的,所以有的数据会在一段时间内只存在于内存中。
appendfsync no/always/everysec ,appendfsync配置,no表示等操作系统进行数据缓存同步到磁盘,always表示每次更新操作后手动调用fsync()将数据写到磁盘,everysec表示每秒同步一次。
两种保存方式dump.rdb (默认snapshot)和 appendonly.aof(每次操作都保存 效率低)
Redis有两种存储方式,默认是snapshot方式,实现方法是定时将内存的快照(snapshot)持久化到硬盘,这种方法缺点是持久化之后如果出现crash则会丢失一段数据。因此在完美主义者的推动下作者增加了aof方式。aof即append only mode,在写入内存数据的同时将操作命令保存到日志文件,在一个并发更改上万的系统中,命令日志是一个非常庞大的数据,管理维护成本非常高,恢复重建时间会非常长,这样导致失去aof高可用性本意。另外更重要的是Redis是一个内存数据结构模型,所有的优势都是建立在对内存复杂数据结构高效的原子操作上,这样就看出aof是一个非常不协调的部分。
...
单线程多进程
代码如何访问?
主流组件:
ServiceStack(1小时3600次请求--可破解)
StackExchange 免费
redis的五大数据结构
String:key-value,支持过期 大小不超过512M
Hash:一个key对应多个 key-value 类似于一个表
Set:无序集合,不能重复 一个key对应多个value
ZSet:有序集合,不能重复,一个key对应多个value ,score,根据Score排序
List:
组合命令 是单条命令
SetAll&AppendToValue&GetValues&GetAndSetValue&IncrementValue&IncrementValueBy,这些看上去是组合命令,但实际上是一个具体的命令,是一个原子性的命令,不可能出现中间状态,可以应对一些并发情况
Decr 不是组合命令 是单条命令,所以redis可以实现超卖
/// <summary> /// 超卖:订单数超过商品 /// ///数据库:秒杀的时候,10件商品,100个人想买,假定大家一瞬间都来了, ///A 查询还有没有--有---1更新 ///B 查询还有没有--有---1更新 ///C 查询还有没有--有---1更新 ///可能会卖出12 12甚至20件商品 /// /// 微服务也有超卖的问题,异步队列 /// /// /// Redis原子性操作--保证一个数值只出现一次--防止一个商品卖给多个人 /// /// /// Redis是单线程,程序怎么又多线程操作Redis呢? 这个是可以的, /// 打开多个链接,去提交任务,对程序而言,Redis是并发 /// /// 假如redis命令是拼装的,Decr---1 获取值 2 程序减1 3 再save结果回去 /// 程序多线程并发一下, A线程 1 2 3 初始值是10 /// B线程 1 2 3 结果是9,减了2次但是结果是9 /// /// 组合命令,Decr Redis线程直接完成当前值-1并返回结果,原子性操作 /// 程序多线程并发一下,A线程 123 初始值10 /// B线程 123 /// C线程 123 得到3个结果,9/8/7 /// /// 假如库存只有1个(数据库),三个人同时来下单,一检测>0,都会成功--超卖 /// 三个人同时来,lock/开启事务 /// 只有一个人能去检测>0 -1 save /// 然后第二个人来,==0 返回失败 /// 然后第三个人来,==0 返回失败 /// 因为这个等于是数据库单线程了,其他都要阻塞,各种超时 /// -1的时候除了操作库存,还得增加订单,等支付。。 /// 10个商品秒杀,一次只能进一个? 违背了业务 /// /// 所以用上了Redis,一方面保证绝对不会超卖, /// 另一方面没有效率影响,数据库是可以为成功的人并发的 /// 还有撤单的时候增加库存,可以继续秒杀, /// 限制秒杀的库存是放在redis,不是数据库,不会造成数据的不一致性 /// /// Redis能够拦截无效的请求,如果没有这一层,所有的请求压力都到数据库 /// /// </summary> public class OversellTest { private static bool IsGoOn = true;//秒杀活动是否结束 public static void Show() { using (RedisStringService service = new RedisStringService()) { service.Set<int>("Stock", 10);//是库存 } for (int i = 0; i < 5000; i++) { int k = i; Task.Run(() =>//每个线程就是一个用户请求 { using (RedisStringService service = new RedisStringService()) { if (IsGoOn) { long index = service.Decr("Stock");//-1并且返回 if (index >= 0) { Console.WriteLine($"{k.ToString("000")}秒杀成功,秒杀商品索引为{index}"); //可以分队列,去数据库操作 } else { if (IsGoOn) { IsGoOn = false; } Console.WriteLine($"{k.ToString("000")}秒杀失败,秒杀商品索引为{index}"); } } else { Console.WriteLine($"{k.ToString("000")}秒杀停止......"); } } }); } Console.Read(); } }
redis文献资料
https://redis.io/documentation
redis命令
https://redis.io/commands#string
redis优化
https://www.infoq.cn/article/tq-redis-memory-usage-optimization-storage/