Redis之品鉴之旅(一)

好知识就如好酒,需要我们坐下来,静静的慢慢的去品鉴。Redis作为主流nosql数据库,在提升性能的方面是不可或缺的。下面就拿好小板凳,我们慢慢的来一一品鉴。

1)redis号称是大数据高并发的利器,那么到底什么是redis?

redis是nosql(not only sql,不仅仅是sql语句),它提供了各种操作的api,不像我们的关系型数据库使用sql语句来操作数据库。

redis全称Remote Dictionary Server(远程字典服务),首先是一个字典,其次是内存数据库(读写速度:CPU>内存>硬盘)。

redis方便扩展,关系型数据库在进行数据扩展时需要 一些列的操作(比如使用了ORM,需要再实体类中增加字段,然后修改dto,修改映射,最后做数据迁移),相对而言redis就会简化很多,只要是数据都可以直接存进去,不需要提前去规范字段。

2)redis8种数据结构:string,hash,list,set,zset,bitmaps,hyperlogloss,streams。前5种是最常用的,后面3中比较少用。

3)redis分布式存储,多台机器实现一个内存共享

4)redis是单线程,但不是redis服务只有一个线程。

单线程的原子性可以理解为不需要锁,不需要上下文切换。单线程就是一个任务一个人做,多线程可以理解成一个任务多个人做,肯定有一个指导这些人去合理做的人。如果需要多线程实现原子性,就会涉及到各种锁、上下文切换 。典型的单线程服务就是nginx,但是在大数据高并发下nginx为什么还是那么的快呢?这就是使用了IO多路复用,redis同样使用,原理一模一样。

后面如果有时间会单独对IO多路复用进行理解。

5)使用的redis客户端的库:ServiceStack.Redis。这个库对客户端的请求操作是有限制的,每小时6000次,但是可以通过修改源码的形式进行限制,不建议反编译dll。

下面我们看一下各种数据结果的API

1)string类型,先上代码

//IP地址,端口,密码,db序号(默认0)
using (RedisClient client = new RedisClient("127.0.0.1", 6379, "12345", 10))
{
//删除当前数据库中的所有Key
client.FlushDb();
//删除所有数据库中的key,慎用
//client.FlushAll();
//统计网站访问数量、当前在线人数、微博数、粉丝数等,全局递增ID等
#region 设置key的value
client.FlushDb();
client.Set<string>("name", "测试数据123");
Console.WriteLine("错误输出");
Console.WriteLine(client.GetValue("name"));
Console.WriteLine("正确输出");
Console.WriteLine(client.Get<string>("name"));
Console.WriteLine(JsonConvert.DeserializeObject<string>(client.GetValue("name"))); //client.Set<int>("keyInt", 123);
//Console.WriteLine("输出1");
//Console.WriteLine(client.GetValue("keyInt"));
//Console.WriteLine("输出2");
//Console.WriteLine(client.Get<int>("keyInt"));
//Console.WriteLine(JsonConvert.DeserializeObject<int>(client.GetValue("keyInt"))); #endregion #region 设置多个key的value
//批量的写入redis key
client.FlushDb();
client.SetAll(new Dictionary<string, string> { { "id", "001" }, { "name", "world" } });
//批量读取内存中多个key的结果 如果我们获取的key不存在,程序会返回一个空的字符串,这redis不会报错
//来判断当前用户是否是老用户
var getall = client.GetAll<string>(new string[] { "id", "name", "number" });
foreach (var item in getall)
{
Console.WriteLine(item);
}
#endregion #region 设置key的value并设置过期时间
client.FlushDb();
client.Set<string>("name", "测试数据123", TimeSpan.FromSeconds(1));
Task.Delay(1 * 1000).Wait();
Console.WriteLine(client.Get<string>("name"));
#endregion #region 设置key的value并设置过期时间 client.FlushDb();
client.Set<string>("name", "测试数据123", DateTime.Now.AddSeconds(1));
Console.WriteLine("刚写进去的结果");
Console.WriteLine(client.Get<string>("name"));
Task.Delay(1 * 1000).Wait();
Console.WriteLine("1秒钟之后的结果");
Console.WriteLine(client.Get<string>("name")); client.Set<string>("class", "优秀班级", TimeSpan.FromSeconds(10));
Task.Delay(1 * 1000).Wait();
Console.WriteLine(client.Get<string>("class"));
#endregion #region 在原有key的value值之后追加value
client.FlushDb();
client.AppendToValue("name3", "I");
client.AppendToValue("name3", " ");
client.AppendToValue("name3", "LOVE YOU");
Console.WriteLine(client.Get<string>("name3"));
#endregion #region 获取旧值赋上新值
client.FlushDb();
client.Set("name", "测试数据123");
//获取当前key的之前的值,然后把新的结果替换进入
var value = client.GetAndSetValue("name", "world");
Console.WriteLine("原先的值" + value);
Console.WriteLine("新值" + client.GetValue("name"));
#endregion #region 自增1,返回自增后的值
//给key为sid的键自增1 ,返回了自增之后的结果,如果键不存在,则默认将初始值赋0,自增之后就是1
client.FlushDb();
Console.WriteLine(client.Incr("sid"));
Console.WriteLine(client.Incr("sid"));
Console.WriteLine(client.Incr("sid"));
Console.WriteLine("华丽丽的结束"); Console.WriteLine(client.GetValue("sid"));
//每次通过传递的count累计,count就是累加的值
client.FlushDb();
client.IncrBy("sid", 2);
Console.WriteLine(client.Get<string>("sid"));
client.IncrBy("sid", 100);
Console.WriteLine("最后的结果***" + client.GetValue("sid"));
#endregion #region 自减1,返回自减后的值
client.FlushDb();
Console.WriteLine(client.Decr("sid"));
Console.WriteLine(client.Decr("sid"));
Console.WriteLine(client.Decr("sid"));
Console.WriteLine("最后的结果" + client.GetValue("sid"));
//通过传入的count去做减肥 之前的结果-count
client.DecrBy("sid", 2);
Console.WriteLine("最终的结果" + client.GetValue("sid"));
#endregion #region add 和set 的区别?
client.FlushDb();
//当使用add 方法去操作redis的时候,如果key存在的话,则不会再次进行操作 返回false 如果操作成功返回true
Console.WriteLine(client.Add("name1", "world"));
//用add的时候帮你去判断如果有则不进行操作,如果没有则写,它只能写新值,不能修改
Console.WriteLine(client.Add("name1", "你很好world"));
Console.WriteLine(client.Get<string>("name1")); //使用set去操作 redis的时候,如果key不存在则写入当前值,并且返回true,通过存在,则对之前的值进行了一个替换 返回操作的结果
Console.WriteLine(client.Set("name2", "world"));
Console.WriteLine(client.Set("name2", "你很好world"));
Console.WriteLine(client.Get<string>("name2"));
#endregion }

注意:尽量不是要使用GetValue,这个api的返回值是带有双引号的内容,那是因为redis默认将数据进行了序列化。这里推荐使用Get泛型的方式进行获取,这里特指的是string类型的数据。而对Int类型的数据,这里返回的结果是一致的。

自减的情况我们可以使用在减库存的场景。set和add的区别:add只做新增的工作,set既能够新增又能够改变。

抢购前景模拟代码:

public static void Show(string id, int minute)
{
#region 自减1,返回自减后的值
//开启10个线程去抢购
Console.WriteLine($"在{minute}分0秒正式开启秒杀!");
var flag = true;
while (flag)
{
if (DateTime.Now.Minute == minute)
{
flag = false;
for (int i = 0; i < 10; i++)
{
string name = $"客户端{id}号:{i}";
Task.Run(() =>
{
using (RedisClient client = new RedisClient("127.0.0.1", 6379, "12345", 10))
{
//本来是二步走
//1 订单+1
//2 库存-1 //同一个时间片。只会执行一条指令
var num = client.Decr("Stock");
if (num < 0)
{
Console.WriteLine(name + "抢购失败");
}
else//>=0
{
Console.WriteLine(name + "**********抢购成功***************");
client.Incr("Order");
}
}
});
Thread.Sleep(10);
}
}
Thread.Sleep(10);
} Console.ReadLine();
#endregion
} //////命令行参数启动
////dotnet RedisSeckill.dll --id=1 minute=03
var builder = new ConfigurationBuilder().AddCommandLine(args);
var configuration = builder.Build();
string id = configuration["id"];
int minute = int.Parse(configuration["minute"]);
Console.WriteLine("开始" + id); using (RedisClient client = new RedisClient("127.0.0.1", 6379, "12345", 10))
{
//首先给数据库预支了秒杀商品的数量,订单数初始为0
client.Set<int>("Stock", 10);
client.Set<int>("Order", 0);
}
Seckill.Show(id, minute); //多个用户抢购结束之后,订单数肯定是10,stock变成了-30,一共抢购了40次,10次成功,30次失败。

在redis内部进行string类型数据存储时,内部有两种数据类型,分别是短数据类型、长数据类型。短数据类型存储时长度是受限制的,长数据类型内部会在string实际长度基础上进行额外空间的开辟,进行空间的预留,这就浪费了数据存储空间。这就是string类型的缺陷。

Redis之品鉴之旅(一)的更多相关文章

  1. Redis之品鉴之旅(七)

    分布式锁 1)阻塞锁: 尝试在redis中创建一个字符串结构缓存,方法传入的key,value为锁的过期时间timeout的时间戳. 若redis中没有这个key,则创建成功(即抢到锁),然后立即返回 ...

  2. Redis之品鉴之旅(六)

    持久化 快照的方式(RDB) 文件追加方式(AOF) 快照形式: save和bgsave能快速的备份数据.但是.........., Save命令:将内存数据镜像保存为rdb文件,由于redis是单线 ...

  3. Redis之品鉴之旅(五)

    Redis事务 原子性:就是最小的单位 一致性:好多命令,要么全部执行成功,要么全部执行失败 隔离性:一个会话和另一个会话之间是互相隔离的 持久性:执行了就执行了,数据保存在硬盘上 典型例子:银行转账 ...

  4. Redis之品鉴之旅(二)

    2)hash类型,上代码 using (RedisClient client = new RedisClient("127.0.0.1", 6379, "12345&qu ...

  5. Redis之品鉴之旅(四)

    发布订阅,简单场景下的发布订阅完全可以使用. 可以简单的理解,将一个公众号视为发布者,关注公众号的人视作订阅者,公众号发布一条文章或者消息,凡事订阅公众号的都可以收到消息.一个人可以订阅多个公众号,一 ...

  6. Redis之品鉴之旅(三)

    3)Set,可以去重的.无序的集合.可以取交集.并集.zset(sorted set),有序的.去重的集合,排序不是根据value排序,而是根据score排序. using (RedisClient ...

  7. tomcat+nginx+redis实现均衡负载、session共享(二)

    今天我们接着说上次还没完成session共享的部分,还没看过上一篇的朋友可以先看下上次内容,http://www.cnblogs.com/zhrxidian/p/5432886.html. 1.red ...

  8. tomcat+nginx+redis实现均衡负载以及session共享

    1.redis简介及下载安装 作为这次的主角,相信大家对redis应该都一定印象,redis是一款开源的高性能key-value数据库,拥有丰富的键值储存类型,并提供多种语言的API. 与一般数据库不 ...

  9. 配置Nginx与tomcat负责均衡集群,

    今天主要说说,nginx如何配置tomcat集群,首先我们先介绍一下各个软件: 一: 1.Nginx介绍: 下载地址:http://nginx.org/en/download.html nginx这个 ...

随机推荐

  1. WPF日积月累之DataGrid样式以及操作数据模板中的控件

    一.效果图 二.代码预览 1 <Window x:Class="Test.MainWindow" 2 xmlns="http://schemas.microsoft ...

  2. C#设计模式---单例模式(Singleton Pattern)

    一.定义 从"单例"字面意思上理解为一个类只有一个实例.官方定义:确保一个类只有一个实例,并提供一个全局访问点. 二.实现 下面以实现一个日志记录类为例,描述单例模式. 1 usi ...

  3. 修改IDEA默认模板

    然后找到你想要修改的模板就可以了

  4. Java Web基础 --- Servlet 综述(理论篇)

    摘要: Web 技术成为当今主流的互联网 Web 应用技术之一,而 Servlet 是 Java Web 技术的核心基础.本文首先从请求/响应架构应用的大背景谈起 Servlet 的由来,明确 Ser ...

  5. docker实现mysql主从复制

    目录 一.概述 二.创建master主库 三.创建Slave实例 四.主从配置 五.参考 一.概述 1.原理 master服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时 ...

  6. QT学习日记篇-02-QT信号和槽

    课程大纲: <1>给控件改名字 随着UI界面的控件变多,如果使用系统自带的名称,后期会让人不明觉厉,说白了,就是掌握C++的命名规则:易懂,条例清晰,人性化 方法:直接点击控件,进入右侧对 ...

  7. element-ui 用 el-checkbox-group 做权限管理

    template <el-checkbox-group v-model="menu_ide" v-for="(item,index) in menu_idss&qu ...

  8. etcd学习(8)-etcd中Lease的续期

    etcd中的Lease 前言 Lease Lease 整体架构 key 如何关联 Lease Lease的续期 过期 Lease 的删除 checkpoint 机制 总结 参考 etcd中的Lease ...

  9. 简单三分钟,本地搭建 k8s

    使用 minikube 在本地搭建 k8s 已经比以前要简单很多了.本文,我们通过简短的三分钟来重现一下在本地搭建 k8s 实验环境的步骤. Newbe.Claptrap 是一个用于轻松应对并发问题的 ...

  10. 遇到Web页面禁用鼠标右键操作时,该如何解禁?

    在使用Selenium做Web UI自动化测试过程中,经常需要鼠标右击Web页面检查DOM节点,用于获取Web元素的定位信息.一般情况下,绝大多数页面都是能够响应鼠标右击操作的.但出于某些目的,有些W ...