一. Geo类型

1. 类型说明

  Geo 是 Redis 3.2 版本后新增的数据类型,用来保存兴趣点(POI,point of interest)的坐标信息。可以实现计算两 POI 之间的距离、获取一个点周边指定距离的 POI。

2. 常用Api

  (1).GeoAdd:添加POI点

  (2).GeoDistance:获取两点之间的最短距离

  (3).GeoPosition:获取某个点的坐标

  (4).GeoRadius:获取某个点(不一定是POI)周边xx米以外的点

  (5).GeoRemove:删除某个点

代码分享:

            //1. 添加所有商店的地理位置
db.GeoAdd("ShopsGeo", new GeoEntry(116.34039, 39.94218, "name1"));
db.GeoAdd("ShopsGeo", new GeoEntry(116.340934, 39.942221, "name2"));
db.GeoAdd("ShopsGeo", new GeoEntry(116.341082, 39.941025, "name3"));
db.GeoAdd("ShopsGeo", new GeoEntry(116.340848, 39.937758, "name4"));
db.GeoAdd("ShopsGeo", new GeoEntry(116.342982, 39.937325, "name5"));
db.GeoAdd("ShopsGeo", new GeoEntry(116.340866, 39.936827, "name6")); //2. 计算商店name1和name2之间的距离(单位m)
double? dist = db.GeoDistance("ShopsGeo", "name1", "name5", GeoUnit.Meters); //3. 获取name1商店的坐标
GeoPosition? pos = db.GeoPosition("ShopsGeo", "name1"); //4. 获取一个 name2 周边的200内的点:
GeoRadiusResult[] results = db.GeoRadius("ShopsGeo", "name2", , GeoUnit.Meters);
foreach (GeoRadiusResult result in results)
{
Console.WriteLine("Id=" + result.Member + ",位置" + result.Position + ",距离" + result.Distance);
} //5. 获取一个坐标(116.34092, 39.94223)(这个坐标不一定是 POI)周边的 POI:
GeoRadiusResult[] results2 = db.GeoRadius("ShopsGeo", 116.34092, 39.94223, , GeoUnit.Meters);
foreach (GeoRadiusResult result in results2)
{
Console.WriteLine("Id=" + result.Member + ",位置" + result.Position + ",距离" + result.Distance);
} //6. 删除
bool d1 = db.GeoRemove("ShopsGeo", "name2");

3. 案例

  地图上点相关的操作,方圆xx米内有多少个商店,某两个商店间的距离

二. Redis批量操作和事务

1. 批量操作

  Batch会把所需要执行的命令打包成一条请求发到Redis,然后一起等待返回结果。这样批量操作的速度就大大提升。 利用CreateBatch和Execute方法,仅支持异步方法哦。

   public static void BatchDemo(IDatabase db)
{
IBatch batch = db.CreateBatch();
batch.StringSetAsync("keen1", "");
batch.StringSetAsync("keen2", "");
batch.Execute(); }

2. 事务

  Redis的操作都是原子性单线程的,如果一次性操作很多,基本上每个方法都支持批量操作,但是如果操作的数据类型不同,可以使用Redis的事务进行包裹。 CreateTransaction和Execute方法

     public static void TransDemo(IDatabase db)
{
var trans = db.CreateTransaction();
trans.StringSetAsync("keen1", "");
trans.StringSetAsync("keen2", );
bool result = trans.Execute();
}

3. 区别 

  批量操作假设里面有一个出错,不会整体回滚,而事务要么都成功,要么都失败。

三. Redis分布式锁

1. 背景

  在传统的单体项目中,即部署到单个IIS上,针对并发问题,比如进销存中的出库和入库问题,多个人同时操作,属于一个IIS进程中多个线程并发操作的问题,这个时候可以引入线程锁lock/Monitor等,轻松解决这类问题。但是随着业务量的逐渐增大,比如"秒杀业务",肯定是集群,这个时候线程锁已经没用了,必须引入分布式锁。

  常见的分布式锁有:数据库、zookeeper、redis。

2. 技术分析

  秒杀业务集群同时访问DB,很容易出现超买超卖问题,如下图: 

 分析:

 

解决方案:

 在秒杀服务集群和DB之间引入Redis(或者Redis集群),无论是Redis单体还是集群,分布式锁都是上一个解锁了下一个才继续加锁,引入Redis集群的目的是防止Redis崩溃,而不是加快速度,这样保证了最终到DB上上的操作是按顺序依次进行的,从而解决了超卖问题。如下图:

 3. 代码实战

  StackExchange.Redis中加锁和解锁的api分别是:LockTake和LockRelease。 bool LockTake(RedisKey key, RedisValue value, TimeSpan expiry, CommandFlags flags = CommandFlags.None); 三个参数的含义分别是:

(1). 锁名

(2). 谁加的的锁

(3). 超时时间,过期自动释放,防止死锁。

代码如下:(加锁的时候要循环获取锁,直到获取为止)

         /// <summary>
/// 分布式锁 业务
/// </summary>
/// <param name="db"></param>
public static void DfsLockDemo(IDatabase db)
{ Lock(db);
try
{
Console.WriteLine("业务执行中......");
Thread.Sleep();
Console.WriteLine("业务执行完毕");
}
catch (Exception)
{
//释放锁
UnLock(db);
}
finally
{
//释放锁
UnLock(db);
}
} /// <summary>
/// 加锁
/// </summary>
/// <param name="db"></param>
public static void Lock(IDatabase db)
{
RedisValue token = Environment.MachineName;
while (true)
{
bool flag = db.LockTake("myLock", token, TimeSpan.FromSeconds()); //10秒后自动释放
if (flag)
{
//表示获取成功,跳出while
break;
}
else
{
Console.WriteLine("获取失败,继续获取");
Thread.Sleep(); }
}
}
/// <summary>
/// 解锁
/// </summary>
/// <param name="db"></param>
public static void UnLock(IDatabase db)
{
RedisValue token = Environment.MachineName;
db.LockRelease("myLock", token);
}

模拟两个项目运行效果:

秒杀案例其它思路或者详细解决方案见:   第六节:秒杀业务/超买超卖的几种解决思路

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 

第四节:Geo类型介绍以及Redis批量操作、事务、分布式锁的更多相关文章

  1. redis客户端、分布式锁及数据一致性

    Redis Java客户端有很多的开源产品比如Redission.Jedis.lettuce等. Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持:Redis ...

  2. redis系列:分布式锁

    redis系列:分布式锁 1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分 ...

  3. 基于Redis的简单分布式锁的原理

    参考资料:https://redis.io/commands/setnx 加锁是为了解决多线程的资源共享问题.Java中,单机环境的锁可以用synchronized和Lock,其他语言也都应该有自己的 ...

  4. redis事务,分布式锁

    事务:一组命令集合 主要命令multi 和exec multi set a 1 sadd s1 a ...... exec 错误处理 (1)语法错误 127.0.0.1:6379> multi ...

  5. 如何用redis正确实现分布式锁?

    先把结论抛出来:redis无法正确实现分布式锁!即使是redis单节点也不行!redis的所谓分布式锁无法用在对锁要求严格的场景下,比如:同一个时间点只能有一个客户端获取锁. 首先来看下单节点下一般r ...

  6. Redis高并发分布式锁详解

    为什么需要分布式锁 1.为了解决Java共享内存模型带来的线程安全问题,我们可以通过加锁来保证资源访问的单一,如JVM内置锁synchronized,类级别的锁ReentrantLock. 2.但是随 ...

  7. 基于redis实现的分布式锁

    基于redis实现的分布式锁 我们知道,在多线程环境中,锁是实现共享资源互斥访问的重要机制,以保证任何时刻只有一个线程在访问共享资源.锁的基本原理是:用一个状态值表示锁,对锁的占用和释放通过状态值来标 ...

  8. 一个Redis实现的分布式锁

    import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.conne ...

  9. Redis系列(二)--分布式锁、分布式ID简单实现及思路

    分布式锁: Redis可以实现分布式锁,只是讨论Redis的实现思路,而真的实现分布式锁,Zookeeper更加可靠 为什么使用分布式锁: 单机环境下只存在多线程,通过同步操作就可以实现对并发环境的安 ...

随机推荐

  1. 编译安装最新版nettle和gnutls

    编译安装最新版gnutls的时候,总是会出libnettle 3.4.1 was not found的报错信息. 即使编译安装了nettle的最新版3.5之后,依然会报该错. 原因是gnutls编译的 ...

  2. 图解servlet

    You can see the following illustration to better understand the lifecycle of the Servlet. When the r ...

  3. 为Dynamics CRM注释的图片附件做个预览功能

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复163或者20151017可方便获取本文,同时可以在第一时间得到我发布的最新的博文信息,follow me! Dynamics CRM中注释可 ...

  4. [转]The Regular Expression Object Model

    本文转自:https://docs.microsoft.com/en-us/dotnet/standard/base-types/the-regular-expression-object-model ...

  5. 微服务:Eureka+Zuul+Ribbon+Feign+Hystrix构建微服务架构

    原文地址:http://blog.csdn.net/qq_18675693/article/details/53282031 本案例将打架一个微服务框架,参考来源官方参考文档 微服务:是什么?网上有一 ...

  6. gyp编译工具

    最近用到了 node-gyp 这个工具, 是node 社区对 google gyp 编译工具的一个封装, 使用 node-gyp 工具可以用C++为node 项目编写 addon. 了解了一下 goo ...

  7. [b0026] python 归纳 (十一)_线程_threading.Thread

    总结: 默认父线程跑完,子线程并不会马上退出,不像 thread.start_threadXXXX 父线程跑完了,并没有退出,一直在那里 线程启动速度很快,不占多少开销,不到1毫 秒 代码: # -* ...

  8. mac上安装npm

    检查brew -v是否安装了homebrew这个macOS 缺失的软件包的管理器.如果安装,跳转到第3步,否则跳转到第二步: 安装homebrew.安装跳转到官网指导.等待安装好之后,输入brew - ...

  9. Prometheus+Grafana监控MySQL、Redis数据库

    俗话说,没有监控的系统就是在裸奔,好的监控就是运维人员的第三只手,第三只眼.本文将使用prometheus及Grafana搭建一套监控系统来监控主机及数据库(MySQL.Redis). 1.  安装G ...

  10. Linux—添加开机启动(服务/脚本)

    系统启动时需要加载的配置文件 /etc/profile./root/.bash_profile/etc/bashrc./root/.bashrc/etc/profile.d/*.sh./etc/pro ...