下面是一些关于Redis比较好的文章,因为篇幅较大,我就将其折叠起来了。不太喜欢分不同的笔记去记载,除非真的很多很多。所以本文不仅要对Redis做简单的介绍,还要分别介绍Redis中的五种结构,并会贴上一些示例代码,因为篇幅比较大,所以示例代码都是折叠起来的,有需要看代码的请自行点开,还请谅解。这里只附上了不分示例代码。

redis.conf配置详细解析https://www.cnblogs.com/kreo/p/4423362.html
项目首页,下方是各种语言支持列表: http://code.google.com/p/redis/ 作者在wiki中给出了一个非常好的例子,以使我们可以快速上手,地址: http://code.google.com/p/redis/wiki/TwitterAlikeExample 同时作者推荐的另一个教程,地址: http://labs.alcacoop.it/doku.php?id=articles:redis_land 一个redis爱好者创建的相关问题讨论网站: http://www.rediscookbook.org/ 为什么使用 Redis及其产品定位 http://www.infoq.com/cn/articles/tq-why-choose-redis Redis内存使用优化与存储 http://www.infoq.com/cn/articles/tq-redis-memory-usage-optimization-storage https://www.linuxidc.com/Linux/2011-02/32700.htm

本地缓存,当前进程的内存,把数据存起来,下次直接使用,可以提升效率。

  1、容量有限,window下面,32位一个进程最多2G或者3G,64位最多也就4G

  2、多服务器直接需要缓存共享,需要分布式缓存,远程服务器内存管理数据,提供读写接口,效率高。

分布式缓存:

  1、Memcached,最早流行的

  2、Redis(NoSQL)现在的主流方案

为什么现在都升级到Redis(NoSQL)去了?

  NoSQL:

    非关系型数据库,Not Only SQL

    web1.0时代,服务端提供数据,客户端看,只能看新闻

    web2.0时代,客户端可以向服务端互动了,现在能评论了

    数据的关系负责:

      好友关系(张三有100个好友,映射表,其实这个映射表就荣誉了,关系型数据库开始累赘了)

      再就是数据库读取和写入压力,硬盘的速度满足不了,尤其是一些大数据量,所以产生了NoSQL。

    特点:基于内存(MongoDB是基于文档的),没有严格的数据格式,不是一行数据的列必须一样。封堵的类型,满足web2.0的需求。

    Redis和MongoDB都是NoSQL,应该在什么场景去选择呢?数据量比较大,用MongoDB,否则其他的一切需求,用Redis就可以解决。

  Redis:REmote DIctionary Server,远程点点服务器,基于内存管理(数据存在内存),实现了五种数据结构(String、HashTable、Set、ZSet、List去分别对应各种具体需求),单线程模型应用程序(单进程单线程),对外提供插入-查询-固化-集群功能。

  Redis----SQLServer

  Redis-Cli---SQLClient

  Redis支持N多个命令,相当于SQL语句

  ServerStack(1小时6000次请求)----ADO.NET

  StackExchange,免费的,其实更像是ORM,封装了连接+命令。

https://github.com/dmajkic/redis/downloads 下载地址

管理员模式打开控制台(配置成自己的路径)

可以打开redis-cli.exe尝试使用,
输入:set key value 
结果:OK
输入:get key 
结果:value

Redis安装与启动,以及可视化管理工具,请参考:https://blog.csdn.net/lihua5419/article/details/80661684

用cli,可以简单的对Redis数据新增和获取

  基于内存管理,速度快,不能当做数据库。Redis还有个固化数据的功能,VitualMemory,把一些不经常访问是会存在硬盘。可以哦诶之的,down掉会丢失数据snapshot可以保存到硬盘。AOF,数据辩护记录日志,很少用。Redis毕竟不是数据库,只能用来提升性能,不能作为数据的最终依据。

多线程模型:

  .NET应用都是多线程模型,尤其是网站,可以更好的发挥硬件的能力,但是也有线冲突的问题和调度成本。

单线程模型:

  Node.js是单线程,整个进程只有一个线程,线程就是执行流,性能低?实际上并非如此。一次网络请求操作----正则解析请求----加减乘除+数据库操作(发命令--等结果),读文件(发命令---等结果)+调用接口(发命令----等结果),单线程都是事件驱动,发起命令就做下一件事,这个线程是完全不做等待的,一直在计算。

  多进程,多进程提供集群;单线程多进程的模式来提供集群服务。,B 查询还有没有--有---1更新

  单线程最大的好处就是原子性操作,就是要么都成功,要么都失败,不会出现中间状态,Redis中的每个命令都是原子性的(因为单线程),不用考虑并发。

C#程序中,要使用Redis,首先要Nuget包安装一些程序集。下面是一些初始化的工作,写法一般都是固定的,我就折叠起来了。

 /// <summary>
/// redis配置文件信息
/// 也可以放到配置文件去
/// </summary>
public sealed class RedisConfigInfo
{
/// <summary>
/// 可写的Redis链接地址
/// format:ip1,ip2
///
/// 默认6379端口
/// </summary>
public string WriteServerList = "127.0.0.1:6379";
/// <summary>
/// 可读的Redis链接地址
/// format:ip1,ip2
/// </summary>
public string ReadServerList = "127.0.0.1:6379";
/// <summary>
/// 最大写链接数
/// </summary>
public int MaxWritePoolSize = ;
/// <summary>
/// 最大读链接数
/// </summary>
public int MaxReadPoolSize = ;
/// <summary>
/// 本地缓存到期时间,单位:秒
/// </summary>
public int LocalCacheTime = ;
/// <summary>
/// 自动重启
/// </summary>
public bool AutoStart = true;
/// <summary>
/// 是否记录日志,该设置仅用于排查redis运行时出现的问题,
/// 如redis工作正常,请关闭该项
/// </summary>
public bool RecordeLog = false;
} /// <summary>
/// Redis管理中心
/// </summary>
public class RedisManager
{
/// <summary>
/// redis配置文件信息
/// </summary>
private static RedisConfigInfo RedisConfigInfo = new RedisConfigInfo(); /// <summary>
/// Redis客户端池化管理
/// </summary>
private static PooledRedisClientManager prcManager; /// <summary>
/// 静态构造方法,初始化链接池管理对象
/// </summary>
static RedisManager()
{
CreateManager();
} /// <summary>
/// 创建链接池管理对象
/// </summary>
private static void CreateManager()
{
string[] WriteServerConStr = RedisConfigInfo.WriteServerList.Split(',');
string[] ReadServerConStr = RedisConfigInfo.ReadServerList.Split(',');
prcManager = new PooledRedisClientManager(ReadServerConStr, WriteServerConStr,
new RedisClientManagerConfig
{
MaxWritePoolSize = RedisConfigInfo.MaxWritePoolSize,
MaxReadPoolSize = RedisConfigInfo.MaxReadPoolSize,
AutoStart = RedisConfigInfo.AutoStart,
});
} /// <summary>
/// 客户端缓存操作对象
/// </summary>
public static IRedisClient GetClient()
{
return prcManager.GetClient();
}
} /// <summary>
/// RedisBase类,是redis操作的基类,继承自IDisposable接口,主要用于释放内存
/// </summary>
public abstract class RedisBase : IDisposable
{
public IRedisClient iClient { get; private set; }
/// <summary>
/// 构造时完成链接的打开
/// </summary>
public RedisBase()
{
iClient = RedisManager.GetClient();
} //public static IRedisClient iClient { get; private set; }
//static RedisBase()
//{
// iClient = RedisManager.GetClient();
//} private bool _disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
iClient.Dispose();
iClient = null;
}
}
this._disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
} public void Transcation()
{
using (IRedisTransaction irt = this.iClient.CreateTransaction())
{
try
{
irt.QueueCommand(r => r.Set("key", ));
irt.QueueCommand(r => r.Increment("key", ));
irt.Commit(); // 提交事务
}
catch (Exception ex)
{
irt.Rollback();
throw ex;
}
}
} /// <summary>
/// 清除全部数据 请小心
/// </summary>
public virtual void FlushAll()
{
iClient.FlushAll();
} /// <summary>
/// 保存数据DB文件到硬盘
/// </summary>
public void Save()
{
iClient.Save();//阻塞式save
} /// <summary>
/// 异步保存数据DB文件到硬盘
/// </summary>
public void SaveAsync()
{
iClient.SaveAsync();//异步save
}
}

Redis中的五大结构

1、String:

  key-value,缓存,支持过期,value不超过512M。Redis单线程的特性,比如SetAll、AppendToValue、GetAndSetValue、IncrementValue、IncrementValueBy,这些命令,看上去是组合命令,实际上是具体的命令,是一个原则性的操作,不用考虑并发,不可能出现中间状态,可以应对一些并发情况。

 现在有个场景,就是超卖的问题,超卖,顾名思义,就是订单数超过商品。

  数据库:秒杀的时候,10件商品,100个人想买,假定大家一瞬间都来了,A 查询还有没有--有---1更新;C 查询还有没有--有---1更新;可能会卖出12  12甚至20件商品;微服务也有超卖的问题,异步队列。Redis原子性操作--保证一个数值只出现一次--防止一个商品卖给多个人

  Redis是单线程的,程序有怎么多线程操作Redis呢?打开多个链接,去提交任务,对程序而言,Redis是并发。所以用上了Redis,一方面保证绝对不会超卖,另一方面没有效率影响,数据库是可以为成功的人并发的,还有撤单的时候增加库存,可以继续秒杀,,限制秒杀的库存是放在redis,不是数据库,不会造成数据的不一致性,Redis能够拦截无效的请求,如果没有这一层,所有的请求压力都到数据库。

超卖的代码示例:

 /// <summary>
/// key-value 键值对:value可以是序列化的数据
/// </summary>
public class RedisStringService : RedisBase
{
#region 赋值
/// <summary>
/// 设置key的value
/// </summary>
public bool Set<T>(string key, T value)
{
return base.iClient.Set<T>(key, value);
}
/// <summary>
/// 设置key的value并设置过期时间
/// </summary>
public bool Set<T>(string key, T value, DateTime dt)
{
return base.iClient.Set<T>(key, value, dt);
}
/// <summary>
/// 设置key的value并设置过期时间
/// </summary>
public bool Set<T>(string key, T value, TimeSpan sp)
{
return base.iClient.Set<T>(key, value, sp);
}
/// <summary>
/// 设置多个key/value
/// </summary>
public void Set(Dictionary<string, string> dic)
{
base.iClient.SetAll(dic);
} #endregion #region 追加
/// <summary>
/// 在原有key的value值之后追加value,没有就新增一项
/// </summary>
public long Append(string key, string value)
{
return base.iClient.AppendToValue(key, value);
}
#endregion #region 获取值
/// <summary>
/// 获取key的value值
/// </summary>
public string Get(string key)
{
return base.iClient.GetValue(key);
}
/// <summary>
/// 获取多个key的value值
/// </summary>
public List<string> Get(List<string> keys)
{
return base.iClient.GetValues(keys);
}
/// <summary>
/// 获取多个key的value值
/// </summary>
public List<T> Get<T>(List<string> keys)
{
return base.iClient.GetValues<T>(keys);
}
#endregion #region 获取旧值赋上新值
/// <summary>
/// 获取旧值赋上新值
/// </summary>
public string GetAndSetValue(string key, string value)
{
return base.iClient.GetAndSetValue(key, value);
}
#endregion #region 辅助方法
/// <summary>
/// 获取值的长度
/// </summary>
public long GetLength(string key)
{
return base.iClient.GetStringCount(key);
}
/// <summary>
/// 自增1,返回自增后的值
/// </summary>
public long Incr(string key)
{
return base.iClient.IncrementValue(key);
}
/// <summary>
/// 自增count,返回自增后的值
/// </summary>
public long IncrBy(string key, int count)
{
return base.iClient.IncrementValueBy(key, count);
}
/// <summary>
/// 自减1,返回自减后的值
/// </summary>
public long Decr(string key)
{
return base.iClient.DecrementValue(key);
}
/// <summary>
/// 自减count ,返回自减后的值
/// </summary>
/// <param name="key"></param>
/// <param name="count"></param>
/// <returns></returns>
public long DecrBy(string key, int count)
{
return base.iClient.DecrementValueBy(key, count);
}
#endregion
}
 public class OversellTest
{
private static bool IsGoOn = true;//秒杀活动是否结束
public static void Show()
{
using (RedisStringService service = new RedisStringService())
{
service.Set<int>("Stock", );//是库存
} for (int i = ; i < ; i++)
{
int k = i;
Task.Run(() =>//每个线程就是一个用户请求
{
using (RedisStringService service = new RedisStringService())
{
if (IsGoOn)
{
long index = service.Decr("Stock");//-1并且返回
if (index >= )
{
Console.WriteLine($"{k.ToString("")}秒杀成功,秒杀商品索引为{index}");
//可以分队列,去数据库操作
}
else
{
if (IsGoOn)
{
IsGoOn = false;
}
Console.WriteLine($"{k.ToString("")}秒杀失败,秒杀商品索引为{index}");
}
}
else
{
Console.WriteLine($"{k.ToString("")}秒杀停止......");
}
}
});
}
Console.Read();
}
} public class OversellField
{
private static bool IsGoOn = true;//秒杀活动是否结束
private static int Stock = ;
public static void Show()
{
Stock = ; for (int i = ; i < ; i++)
{
int k = i;
Task.Run(() =>//每个线程就是一个用户请求
{
if (IsGoOn)
{
long index = Stock;//-1并且返回 去数据库查一下当前的库存
Thread.Sleep(); if (index >= )
{
Stock = Stock - ;//更新库存
Console.WriteLine($"{k.ToString("")}秒杀成功,秒杀商品索引为{index}");
//可以分队列,去数据库操作
}
else
{
if (IsGoOn)
{
IsGoOn = false;
}
Console.WriteLine($"{k.ToString("")}秒杀失败,秒杀商品索引为{index}");
}
}
else
{
Console.WriteLine($"{k.ToString("")}秒杀停止......");
}
});
}
Console.Read();
}
}

2、Hash

  

key-dictionary

  1、节约空间(zipmap的紧密摆放的存储模式)

  2、更新/访问方便(hashid+key)

  3、Hash数据结构很想关系型数据库的一张表的一行数据。但是其实字段是可以随意定制的,没有严格约束。

缓存一个用户的信息,用String类型可以吗?也可以,因为String类型,key-value,先序列化,然后再反序列化,然后存储:

 using (RedisStringService service = new RedisStringService())
{
//service.Set<string>($"userinfo_{user.Id}", Newtonsoft.Json.JsonConvert.SerializeObject(user));
service.Set<UserInfo>($"userinfo_{user.Id}", user);
var userCacheList = service.Get<UserInfo>(new List<string>() { $"userinfo_{user.Id}" });
var userCache = userCacheList.FirstOrDefault();
//string sResult = service.Get($"userinfo_{user.Id}");
//var userCache = Newtonsoft.Json.JsonConvert.DeserializeObject<UserInfo>(sResult);
userCache.Account = "Admin";
service.Set<UserInfo>($"userinfo_{user.Id}", userCache);
}

如果修改需求,就是查询---反序列化---修改---序列化---存储。这样真的太麻烦了。

现在有了Hash类型。

using (RedisHashService service = new RedisHashService())
{
service.SetEntryInHash("student", "id", "bingle1");
service.SetEntryInHash("student", "name", "bingle2");
service.SetEntryInHash("student", "remark", "bingle3"); var keys = service.GetHashKeys("student");
var values = service.GetHashValues("student");
var keyValues = service.GetAllEntriesFromHash("student");
Console.WriteLine(service.GetValueFromHash("student", "id")); service.SetEntryInHashIfNotExists("student", "name", "bingle");
service.SetEntryInHashIfNotExists("student", "description", "bingle"); Console.WriteLine(service.GetValueFromHash("student", "name"));
Console.WriteLine(service.GetValueFromHash("student", "description"));
service.RemoveEntryFromHash("student", "description");
Console.WriteLine(service.GetValueFromHash("student", "description"));
}

Hash---》Hashid---UserInfo  

多个key,String类型的value,最小是512byte,即使只保存一个1,也要占用512byte的空间。而hash是一种zipmap存储,数据紧密排列,可以节约空间(配置zip两个属性,只要都满足就可以用zipmap存储)。

Hash的有点:

  1、节约空间

  2、更新方便

如果实体类型是带ID的,可以直接实体存储和读取。

 using (RedisHashService service = new RedisHashService())
{
service.FlushAll();
//反射遍历做一下
service.SetEntryInHash($"userinfo_{user.Id}", "Account", user.Account);
service.SetEntryInHash($"userinfo_{user.Id}", "Name", user.Name);
service.SetEntryInHash($"userinfo_{user.Id}", "Address", user.Address);
service.SetEntryInHash($"userinfo_{user.Id}", "Email", user.Email);
service.SetEntryInHash($"userinfo_{user.Id}", "Password", user.Password);
service.SetEntryInHash($"userinfo_{user.Id}", "Account", "Admin"); service.StoreAsHash<UserInfo>(user);//含ID才可以的
var result = service.GetFromHash<UserInfo>(user.Id); }

3、Set

 using (RedisSetService service = new RedisSetService())
{
service.FlushAll();//清理全部数据 service.Add("advanced", "");
service.Add("advanced", "");
service.Add("advanced", "");
service.Add("advanced", "");
service.Add("advanced", "");
service.Add("advanced", "");
service.Add("advanced", ""); var result = service.GetAllItemsFromSet("advanced"); var random = service.GetRandomItemFromSet("advanced");//随机获取
service.GetCount("advanced");//独立的ip数
service.RemoveItemFromSet("advanced", ""); {
service.Add("begin", "");
service.Add("begin", "");
service.Add("begin", ""); service.Add("end", "");
service.Add("end", "");
service.Add("end", ""); var result1 = service.GetIntersectFromSets("begin", "end");
var result2 = service.GetDifferencesFromSet("begin", "end");
var result3 = service.GetUnionFromSets("begin", "end");
//共同好友 共同关注
}
}

好友管理,共同好友,可能认识

去重:IP统计去重;添加好友申请;投票限制;点赞。

4、ZSet:是一个有序集合,去重

  

using (RedisZSetService service = new RedisZSetService())
{
service.FlushAll();//清理全部数据 service.Add("advanced", "");
service.Add("advanced", "");
service.Add("advanced", "");
service.Add("advanced", "");
service.Add("advanced", "");
service.Add("advanced", "");
service.Add("advanced", ""); var result1 = service.GetAll("advanced");
var result2 = service.GetAllDesc("advanced"); service.AddItemToSortedSet("Sort", "bingle1", );
service.AddItemToSortedSet("Sort", "bingle2", );
service.AddItemToSortedSet("Sort", "bingle3", );
service.AddItemToSortedSet("Sort", "bingle4", );
service.AddItemToSortedSet("Sort", "bingle5", );
service.AddRangeToSortedSet("Sort", new List<string>() { "", "花生", "加菲猫" }, );
var result3 = service.GetAllWithScoresFromSortedSet("Sort"); //交叉并
}

最后一个参数,是自己设定的,设定value的分数的。

实时排行榜:刷个礼物。

维度很多,平台/房间/主播/日/周/年/月

A对B刷个礼物,影响很多。

没Redis之前,刷个礼物值记录流水,不影响排行,凌晨24点跑任务更新。

实时排行榜,Redis-IncrementItemInSortedSet,刷礼物增加Redis分数,就可以试试获取最新的排行,多个维度就是多个ZSet,刷礼物的时候保存数据库并更新Redis。

5、List

  

生产者消费者:

using (RedisListService service = new RedisListService())
{
service.Add("test", "这是一个学生Add1");
service.Add("test", "这是一个学生Add2");
service.Add("test", "这是一个学生Add3"); service.LPush("test", "这是一个学生LPush1");
service.LPush("test", "这是一个学生LPush2");
service.LPush("test", "这是一个学生LPush3");
service.LPush("test", "这是一个学生LPush4");
service.LPush("test", "这是一个学生LPush5");
service.LPush("test", "这是一个学生LPush6"); service.RPush("test", "这是一个学生RPush1");
service.RPush("test", "这是一个学生RPush2");
service.RPush("test", "这是一个学生RPush3");
service.RPush("test", "这是一个学生RPush4");
service.RPush("test", "这是一个学生RPush5");
service.RPush("test", "这是一个学生RPush6"); List<string> stringList = new List<string>();
for (int i = ; i < ; i++)
{
stringList.Add(string.Format($"放入任务{i}"));
}
service.Add("task", stringList); Console.WriteLine(service.Count("test"));
Console.WriteLine(service.Count("task"));
var list = service.Get("test");
list = service.Get("task", , ); Action act = new Action(() =>
{
while (true)
{
Console.WriteLine("************请输入数据**************");
string testTask = Console.ReadLine();
service.LPush("test", testTask);
}
});
act.EndInvoke(act.BeginInvoke(null, null));
}

生产者消费者(队列)一个数据,只能被一个对象消费,一个程序写入,一个程序即时读取消费,还可以多个程序读取消费,按照时间顺序,数据失败了还可以放回去下次重试,这种东西在项目中有什么价值呢?和那些MQ差不多,就是队列。

异步队列:

  优点:

    1、可以控制并发数量

    2、以前要求立马处理完,现在可以在一个时段完成

    3、失败还能重试

    4、流量削峰,降低高峰期的压力

    5、高可用

    6、可扩展

  缺点:

    1、不能理解处理

    2、事务的一致性问题。

发布订阅,发布一个数据,全部的订阅者都能收到。观察者,一个数据源,多个接受者,只要订阅了就可以收到的,能被多个数据源共享。观察者模式:微信订阅号---群聊天----数据同步

MSMQ---RabbitMQ---ZeroMQ----RocketMQ---RedisList

分布式缓存,多个服务器都可以访问到,多个生产者,多个消费者,任何产品只被消费一次。

 using (RedisListService service = new RedisListService())
{ service.Add("test", "这是一个学生Add1");
service.Add("test", "这是一个学生Add2");
service.Add("test", "这是一个学生Add3"); service.LPush("test", "这是一个学生LPush1");
service.LPush("test", "这是一个学生LPush2");
service.LPush("test", "这是一个学生LPush3");
service.LPush("test", "这是一个学生LPush4");
service.LPush("test", "这是一个学生LPush5");
service.LPush("test", "这是一个学生LPush6"); service.RPush("test", "这是一个学生RPush1");
service.RPush("test", "这是一个学生RPush2");
service.RPush("test", "这是一个学生RPush3");
service.RPush("test", "这是一个学生RPush4");
service.RPush("test", "这是一个学生RPush5");
service.RPush("test", "这是一个学生RPush6"); List<string> stringList = new List<string>();
for (int i = ; i < ; i++)
{
stringList.Add(string.Format($"放入任务{i}"));
}
service.Add("task", stringList); Console.WriteLine(service.Count("test"));
Console.WriteLine(service.Count("task"));
var list = service.Get("test");
list = service.Get("task", , ); //Action act = new Action(() =>
//{
// while (true)
// {
// Console.WriteLine("************请输入数据**************");
// string testTask = Console.ReadLine();
// service.LPush("test", testTask);
// Console.ReadLine();
// }
//});
//act.EndInvoke(act.BeginInvoke(null, null)); while (true)
{
Console.WriteLine("************请输入数据**************");
string testTask = Console.ReadLine();
service.LPush("test", testTask);
} }
 public class ServiceStackProcessor
{
public static void Show()
{
string path = AppDomain.CurrentDomain.BaseDirectory;
string tag = path.Split('/', '\\').Last(s => !string.IsNullOrEmpty(s));
Console.WriteLine($"这里是 {tag} 启动了。。");
using (RedisListService service = new RedisListService())
{
Action act = new Action(() =>
{
while (true)
{
var result = service.BlockingPopItemFromLists(new string[] { "test", "task" }, TimeSpan.FromHours());
Thread.Sleep();
Console.WriteLine($"这里是 {tag} 队列获取的消息 {result.Id} {result.Item}");
}
});
act.EndInvoke(act.BeginInvoke(null, null));
}
} }

ask项目,问答,一天的问题都是几万,表里面是几千万数据,首页要战士最新的问题,Ajax动态定时获取刷新,还有前20也是很多人访问的。

每次写入数据库的时候,把ID_标题写到RedisList,后面搞个TrimList,只要最近200个,用户刷新页面的时候就不需要去数据库了,直接Redis。

还有一种就是水平分表,第一次的时候不管分页,只拿数据,存数据的时候可以保存id+表全名。

主要解决数据量大,变化的数据分页问题。二八原则,80%的访问集中在20%的数据,List里面只用保存大概的量就够了。

Redis缓存NoSQL的更多相关文章

  1. NoSQL:Redis缓存、雪崩、击穿、穿透

    Redis介绍 Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库 ...

  2. Redis缓存服务搭建及实现数据读写

    发现博客园中好多大牛在介绍自己的开源项目是很少用到缓存,比如Memcached.Redis.mongodb等,今天得空抽时间把Redis缓存研究了一下,写下来总结一下,跟大家一起分享 一下.由于小弟水 ...

  3. Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势

    作者:13 GitHub:https://github.com/ZHENFENG13 版权声明:本文为原创文章,未经允许不得转载. 简介 这是一篇关于Redis使用的总结类型文章,会先简单的谈一下缓存 ...

  4. Spring Data Redis 让 NoSQL 快如闪电 (1)

    [编者按]本文作者为 Xinyu Liu,详细介绍了 Redis 的特性,并辅之以丰富的用例.在本文的第一部分,将重点概述 Redis 的方方面面.文章系国内 ITOM 管理平台 OneAPM 编译呈 ...

  5. Redis缓存机制

    Redis介绍 Redis是一款内存高速缓存数据库: 数据模型为:key - value,非关系型数据库使用的存储数据的格式: 可持久化:将内存数据在写入之后按照一定格式存储在磁盘文件中,宕机.断电后 ...

  6. 如约而至,Java 10 正式发布! Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势 努力的孩子运气不会太差,跌宕的人生定当更加精彩 优先队列详解(转载)

    如约而至,Java 10 正式发布!   3 月 20 日,Oracle 宣布 Java 10 正式发布. 官方已提供下载:http://www.oracle.com/technetwork/java ...

  7. redis缓存介绍以及常见问题浅析

    # 没缓存的日子: 对于web来说,是用户量和访问量支持项目技术的更迭和前进.随着服务用户提升.可能会出现一下的一些状况: 页面并发量和访问量并不多,mysql足以支撑自己逻辑业务的发展.那么其实可以 ...

  8. redis缓存, 缓存击穿,缓存雪崩,缓存穿透

    在实际项目中,MySQL数据库服务器有时会位于另外一台主机,需要通过网络来访问数据库:即使应用程序与MySQL数据库在同一个主机中,访问MySQL也涉及到磁盘IO操作(MySQL也有一些数据预读技术, ...

  9. Redis缓存穿透、缓存雪崩、redis并发问题 并发竞争key的解决方案 (阿里)

    阿里的人问我 缓存雪崩(大量数据在同一时间过期了)了如何处理,缓存击穿了如何处理,回答的很烂,做了总结: 把redis作为缓存使用已经是司空见惯,但是使用redis后也可能会碰到一系列的问题,尤其是数 ...

随机推荐

  1. 使用python实现http服务器

    主要使用python实现了一个http服务器.http服务器实现了用户的注册和登录的简单功能,当然还可以继续扩展. 数据的存储使用的是文件,有兴趣的话可以使用数据库进行存储.当然根据个人兴趣而定. 本 ...

  2. hibernate查询方式(二)

    1.HQL查询(hibernate query language) 操作的是实体类和属性 *查询所有记录 //1.hql查询操作会使用Query对象 // (1)写sql语句 创建Query对象, S ...

  3. GIS学习汇总

    GIS之家: Geoserver: geoserver安装部署步骤 geoserver发布地图服务WMS geoserver发布地图服务WMTS geoserver集成以及部署arcgis serve ...

  4. 尺取法two pointers

    目的:对给定的一个序列,在序列中寻找包含全部需求的.长度最小的一段子序列.一般用来解决具有单调性的区间问题. 时间复杂度:O(n) https://blog.csdn.net/lxt_lucia/ar ...

  5. (全国多校重现赛一)E-FFF at Valentine

    At Valentine's eve, Shylock and Lucar were enjoying their time as any other couples. Suddenly, LSH, ...

  6. mui 顶部选项卡的两种切换方式

    mui 顶部选项卡的两种切换方式 第一种main页面 <!DOCTYPE html> <html> <head> <meta charset="ut ...

  7. C#异步编程看这篇就够了

    随着.NET Core的流行,相信你现在的代码中或多或少的会用到async以及await吧!毕竟已成标配.那么我们为什么要用async以及await呢?其实这是微软团队为我们提供的一个语法糖,让我们不 ...

  8. Selenium之ActionChains类、Keys类

    ActionChains类(鼠标操作)常用于模拟鼠标的行为,比如单击.双击.拖拽等行为. 一些常用的模拟鼠标的操作方法有: click(on_element=None)     --- 鼠标单击 do ...

  9. Vue如何实现数据响应的

    参考博客:https://medium.com/vue-mastery/the-best-explanation-of-javascript-reactivity-fea6112dd80d 翻译博客: ...

  10. iOS Charts 折线图框架的基本使用

    1. 导入框架 通过 cocoapods 管理应用程序时,在 Podfile 文件中,use_frameworks! 的使用区别如下: 使用 use_frameworks! 时 dynamic fra ...