zoukankan      html  css  js  c++  java
  • 第四节:Geo类型介绍以及Redis批量操作、事务、分布式锁

    一. 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            //1. 添加所有商店的地理位置
     2             db.GeoAdd("ShopsGeo", new GeoEntry(116.34039, 39.94218, "name1"));
     3             db.GeoAdd("ShopsGeo", new GeoEntry(116.340934, 39.942221, "name2"));
     4             db.GeoAdd("ShopsGeo", new GeoEntry(116.341082, 39.941025, "name3"));
     5             db.GeoAdd("ShopsGeo", new GeoEntry(116.340848, 39.937758, "name4"));
     6             db.GeoAdd("ShopsGeo", new GeoEntry(116.342982, 39.937325, "name5"));
     7             db.GeoAdd("ShopsGeo", new GeoEntry(116.340866, 39.936827, "name6"));
     8 
     9             //2. 计算商店name1和name2之间的距离(单位m)
    10             double? dist = db.GeoDistance("ShopsGeo", "name1", "name5", GeoUnit.Meters);
    11 
    12             //3. 获取name1商店的坐标
    13             GeoPosition? pos = db.GeoPosition("ShopsGeo", "name1");
    14 
    15             //4. 获取一个 name2 周边的200内的点: 
    16             GeoRadiusResult[] results = db.GeoRadius("ShopsGeo", "name2", 200, GeoUnit.Meters);
    17             foreach (GeoRadiusResult result in results)
    18             {
    19                 Console.WriteLine("Id=" + result.Member + ",位置" + result.Position + ",距离" + result.Distance);
    20             }
    21 
    22             //5.  获取一个坐标(116.34092, 39.94223)(这个坐标不一定是 POI)周边的 POI: 
    23             GeoRadiusResult[] results2 = db.GeoRadius("ShopsGeo", 116.34092, 39.94223, 200, GeoUnit.Meters);
    24             foreach (GeoRadiusResult result in results2)
    25             {
    26                 Console.WriteLine("Id=" + result.Member + ",位置" + result.Position + ",距离" + result.Distance);
    27             }
    28 
    29             //6. 删除
    30             bool d1 = db.GeoRemove("ShopsGeo", "name2");

    3. 案例

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

     

    二. Redis批量操作和事务

    1. 批量操作

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

    1   public static void BatchDemo(IDatabase db)
    2   {
    3     IBatch batch = db.CreateBatch();
    4     batch.StringSetAsync("keen1", "111");
    5     batch.StringSetAsync("keen2", "222");
    6     batch.Execute();
    7 
    8   }

    2. 事务

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

    1     public static void TransDemo(IDatabase db)
    2     {
    3             var trans = db.CreateTransaction();
    4             trans.StringSetAsync("keen1", "111");
    5             trans.StringSetAsync("keen2", 222);
    6             bool result = trans.Execute();
    7       }

    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). 超时时间,过期自动释放,防止死锁。

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

     1         /// <summary>
     2         /// 分布式锁 业务
     3         /// </summary>
     4         /// <param name="db"></param>
     5         public static void DfsLockDemo(IDatabase db)
     6         {
     7 
     8             Lock(db);
     9             try
    10             {
    11                 Console.WriteLine("业务执行中......");
    12                 Thread.Sleep(8000);
    13                 Console.WriteLine("业务执行完毕");
    14             }
    15             catch (Exception)
    16             {
    17                 //释放锁
    18                 UnLock(db);
    19             }
    20             finally
    21             {
    22                 //释放锁
    23                 UnLock(db);
    24             }
    25         }
    26 
    27         /// <summary>
    28         /// 加锁
    29         /// </summary>
    30         /// <param name="db"></param>
    31         public static void Lock(IDatabase db)
    32         {
    33             RedisValue token = Environment.MachineName;
    34             while (true)
    35             {
    36                 bool flag = db.LockTake("myLock", token, TimeSpan.FromSeconds(10)); //10秒后自动释放
    37                 if (flag)
    38                 {
    39                     //表示获取成功,跳出while
    40                     break;
    41                 }
    42                 else
    43                 {
    44                     Console.WriteLine("获取失败,继续获取");
    45                     Thread.Sleep(200);
    46 
    47                 }
    48             }
    49         }
    50         /// <summary>
    51         /// 解锁
    52         /// </summary>
    53         /// <param name="db"></param>
    54         public static void UnLock(IDatabase db)
    55         {
    56             RedisValue token = Environment.MachineName;
    57             db.LockRelease("myLock", token);
    58         }

    模拟两个项目运行效果:

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

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    话题: 工人重度烧伤 厂方疑暗示“安乐死”后再赔偿
    Linux下使用mail命令发送邮件
    跨境电商优秀网站
    smarty模版使用php标签,如何获取模版变量
    弹窗效果处理和改进
    Keepalived + MySQLfailover + GTIDs 高可用
    linux的常用命令
    linux简单介绍,helloworld,vi使用,用户管理
    linux语言设置i18n(转)
    丢手帕问题
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/11946747.html
Copyright © 2011-2022 走看看