广告
返回顶部
首页 > 资讯 > 数据库 >Redis如何实现“附近的人”功能
  • 280
分享到

Redis如何实现“附近的人”功能

2024-04-02 19:04:59 280人浏览 泡泡鱼
摘要

这篇文章给大家分享的是有关Redis如何实现“附近的人”功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。针对“附近的人”这一位置服务领域的应用场景,常见的可使用PG、Mysql

这篇文章给大家分享的是有关Redis如何实现“附近的人”功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

针对“附近的人”这一位置服务领域的应用场景,常见的可使用PG、MysqlmongoDB等多种DB的空间索引进行实现。而Redis另辟蹊径,结合其有序队列zset以及geohash编码,实现了空间搜索功能,且拥有极高的运行效率。本文将从源码角度对其算法原理进行解析,并推算查询时间复杂度。

操作命令

自Redis 3.2开始,Redis基于geohash和有序集合提供了地理位置相关功能。

Redis Geo模块包含了以下6个命令:

GEOADD: 将给定的位置对象(纬度、经度、名字)添加到指定的key;

GEOPOS: 从key里面返回所有给定位置对象的位置(经度和纬度);

GEODIST: 返回两个给定位置之间的距离;

GEOHASH: 返回一个或多个位置对象的Geohash表示;

GEORADIUS: 以给定的经纬度为中心,返回目标集合中与中心的距离不超过给定最大距离的所有位置对象;

GEORADIUSBYMEMBER: 以给定的位置对象为中心,返回与其距离不超过给定最大距离的所有位置对象。

其中,组合使用GEOADD和GEORADIUS可实现“附近的人”中“增”和“查”的基本功能。要实现微信中“附近的人”功能,可直接使用GEORADIUSBYMEMBER命令。其中“给定的位置对象”即为用户本人,搜索的对象为其他用户。不过本质上,GEORADIUSBYMEMBER = GEOPOS + GEORADIUS,即先查找用户位置再通过该位置搜索附近满足位置相互距离条件的其他用户对象。

以下会从源码角度入手对GEOADD和GEORADIUS命令进行分析,剖析其算法原理。

Redis geo操作中只包含了“增”和“查”的操作,并没有专门的“删除”命令。主要是因为Redis内部使用有序集合(zset)保存位置对象,可用zrem进行删除。

在Redis源码geo.c的文件注释中,只说明了该文件为GEOADD、GEORADIUS和GEORADIUSBYMEMBER的实现文件(其实在也实现了另三个命令)。从侧面看出其他三个命令为辅助命令。

GEOADD

使用方式

GEOADD key longitude latitude member [longitude latitude member ...]

将给定的位置对象(纬度、经度、名字)添加到指定的key。

其中,key为集合名称,member为该经纬度所对应的对象。在实际运用中,当所需存储的对象数量过多时,可通过设置多key(如一个省一个key)的方式对对象集合变相做sharding,避免单集合数量过多。

成功插入后的返回值:

(integer) N

其中N为成功插入的个数。

源码分析


void geoaddCommand(client *c) {
//参数校验
  
  if ((c->arGC - 2) % 3 != 0) {
    
    addReplyError(c, "syntax error. Try GEOADD key [x1] [y1] [name1] "
             "[x2] [y2] [name2] ... ");
    return;
  }
//参数提取Redis
  int elements = (c->argc - 2) / 3;
  int argc = 2+elements*2; 
  robj **argv = zcalloc(argc*sizeof(robj*));
  argv[0] = createRawStrinGobject("zadd",4);
  argv[1] = c->argv[1]; 
  incrRefCount(argv[1]);
//参数遍历+转换
  
  int i;
  for (i = 0; i < elements; i++) {
    double xy[2];
  //提取经纬度
    if (extractLongLatOrReply(c, (c->argv+2)+(i*3),xy) == C_ERR) {
      for (i = 0; i < argc; i++)
        if (argv[i]) decrRefCount(argv[i]);
      zfree(argv);
      return;
    }
  //将经纬度转换为52位的geohash作为分值 & 提取对象名称
    
    GeoHashBits hash;
    geohashEncodeWGS84(xy[0], xy[1], GEO_STEP_MAX, &hash);
    GeoHashFix52Bits bits = geohashAlign52Bits(hash);
    robj *score = createObject(OBJ_STRING, sdsfromlonglong(bits));
    robj *val = c->argv[2 + i * 3 + 2];
  //设置有序集合的对象元素名称和分值
    argv[2+i*2] = score;
    argv[3+i*2] = val;
    incrRefCount(val);
  }
//调用zadd命令,存储转化好的对象
  
  replaceClientCommandVector(c,argc,argv);
  zaddCommand(c);
}

通过源码分析可以看出Redis内部使用有序集合(zset)保存位置对象,有序集合中每个元素都是一个带位置的对象,元素的score值为其经纬度对应的52位的geohash值。

double类型精度为52位;

geohash是以base32的方式编码,52bits最高可存储10位geohash值,对应地理区域大小为0.6*0.6米的格子。换句话说经Redis geo转换过的位置理论上会有约0.3*1.414=0.424米的误差。

算法小结

总结下GEOADD命令都干了啥:

1、参数提取和校验;

2、将入参经纬度转换为52位的geohash值(score);

3、调用ZADD命令将member及其对应的score存入集合key中。

GEORADIUS

使用方式

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count] [STORE key] [STORedisT key]

以给定的经纬度为中心,返回目标集合中与中心的距离不超过给定最大距离的所有位置对象。

范围单位:m | km | ft | mi --> 米 | 千米 | 英尺 | 英里

额外参数:

- WITHDIST:在返回位置对象的同时,将位置对象与中心之间的距离也一并返回。距离的单位和用户给定的范围单位保持一致。

- WITHCOORD:将位置对象的经度和维度也一并返回。

- WITHHASH:以 52 位有符号整数的形式,返回位置对象经过原始 geohash 编码的有序集合分值。这个选项主要用于底层应用或者调试,实际中的作用并不大。

- ASC|DESC:从近到远返回位置对象元素 | 从远到近返回位置对象元素。

- COUNT count:选取前N个匹配位置对象元素。(不设置则返回所有元素)

- STORE key:将返回结果的地理位置信息保存到指定key。

- STORedisT key:将返回结果离中心点的距离保存到指定key。

由于 STORE 和 STORedisT 两个选项的存在,GEORADIUS 和 GEORADIUSBYMEMBER 命令在技术上会被标记为写入命令,从而只会查询(写入)主实例,QPS过高时容易造成主实例读写压力过大。

为解决这个问题,在 Redis 3.2.10 和 Redis 4.0.0 中,分别新增了 GEORADIUS_RO 和 GEORADIUSBYMEMBER_RO两个只读命令。

成功查询后的返回值:

不带WITH限定,返回一个member list,如:

["member1","member2","member3"]

带WITH限定,member list中每个member也是一个嵌套list,如:

[
["member1", distance1, [longitude1, latitude1]]
["member2", distance2, [longitude2, latitude2]]
]

源码分析

此段源码较长,看不下去的可直接看中文注释,或直接跳到小结部分


void georadiusGeneric(client *c, int flags) {
  robj *key = c->argv[1];
  robj *storekey = NULL;
  int stoRedist = 0; 
//根据key获取有序集合
  robj *zobj = NULL;
  if ((zobj = lookupKeyReadOrReply(c, key, shared.null[c->resp])) == NULL ||
    checkType(c, zobj, OBJ_ZSET)) {
    return;
  }
//根据用户输入(经纬度/member)确认中心点经纬度
  int base_args;
  double xy[2] = { 0 };
  if (flags & RADIUS_COORDS) {
……
  }
//获取查询范围距离
  double radius_meters = 0, conversion = 1;
  if ((radius_meters = extractDistanceOrReply(c, c->argv + base_args - 2,
                        &conversion)) < 0) {
    return;
  }
//获取可选参数 (withdist、withhash、withcoords、sort、count)
  int withdist = 0, withhash = 0, withcoords = 0;
  int sort = SORT_NONE;
  long long count = 0;
  if (c->argc > base_args) {
    ... ...
  }
//获取 STORE 和 STORedisT 参数
  if (storekey && (withdist || withhash || withcoords)) {
    addReplyError(c,
      "STORE option in GEORADIUS is not compatible with "
      "WITHDIST, WITHHASH and WITHCOORDS options");
    return;
  }
//设定排序
  if (count != 0 && sort == SORT_NONE) sort = SORT_ASC;
//利用中心点和半径计算目标区域范围
  GeoHashRadius georadius =
    geohashGetAreasByRadiusWGS84(xy[0], xy[1], radius_meters);
//对中心点及其周围8个geohash网格区域进行查找,找出范围内元素对象
  geoArray *ga = geoArrayCreate();
  membersOfAllNeighbors(zobj, georadius, xy[0], xy[1], radius_meters, ga);
//未匹配返空
  
  if (ga->used == 0 && storekey == NULL) {
    addReplyNull(c);
    geoArrayFree(ga);
    return;
  }
//一些返回值的设定和返回
  ……
  geoArrayFree(ga);
}

上文代码中最核心的步骤有两个,一是“计算中心点范围”,二是“对中心点及其周围8个geohash网格区域进行查找”。对应的是geohashGetAreasByRadiusWGS84和membersOfAllNeighbors两个函数。我们依次来看:

计算中心点范围:

// geohash_helper.c
GeoHashRadius geohashGetAreasByRadiusWGS84(double longitude, double latitude,
                      double radius_meters) {
  return geohashGetAreasByRadius(longitude, latitude, radius_meters);
}
//返回能够覆盖目标区域范围的9个geohashBox
GeoHashRadius geohashGetAreasByRadius(double longitude, double latitude, double radius_meters) {
//一些参数设置
  GeoHashRange long_range, lat_range;
  GeoHashRadius radius;
  GeoHashBits hash;
  GeoHashNeighbors neighbors;
  GeoHashArea area;
  double min_lon, max_lon, min_lat, max_lat;
  double bounds[4];
  int steps;
//计算目标区域外接矩形的经纬度范围(目标区域为:以目标经纬度为中心,半径为指定距离的圆)
  geohashBoundingBox(longitude, latitude, radius_meters, bounds);
  min_lon = bounds[0];
  min_lat = bounds[1];
  max_lon = bounds[2];
  max_lat = bounds[3];
//根据目标区域中心点纬度和半径,计算带查询的9个搜索框的geohash精度(位)
//这里用到latitude主要是针对极地的情况对精度进行了一些调整(纬度越高,位数越小)
  steps = geohashEstimateStepsByRadius(radius_meters,latitude);
//设置经纬度最大最小值:-180<=longitude<=180, -85<=latitude<=85
  geohashGetCoordRange(&long_range,&lat_range);
//将待查经纬度按指定精度(steps)编码成geohash值
  geohashEncode(&long_range,&lat_range,longitude,latitude,steps,&hash);
//将geohash值在8个方向上进行扩充,确定周围8个Box(neighbors)
  geohashNeighbors(&hash,&neighbors);
//根据hash值确定area经纬度范围
  geohashDecode(long_range,lat_range,hash,&area);
//一些特殊情况处理
  ……
//构建并返回结果  
  radius.hash = hash;
  radius.neighbors = neighbors;
  radius.area = area;
  return radius;
}

对中心点及其周围8个geohash网格区域进行查找:

// geo.c
//在9个hashBox中获取想要的元素
int membersOfAllNeighbors(robj *zobj, GeoHashRadius n, double lon, double lat, double radius, geoArray *ga) {
  GeoHashBits neighbors[9];
  unsigned int i, count = 0, last_processed = 0;
  int debugmsg = 0;
//获取9个搜索hashBox
  neighbors[0] = n.hash;
  neighbors[8] = n.neighbors.south_west;
//在每个hashBox中搜索目标点
  for (i = 0; i < sizeof(neighbors) / sizeof(*neighbors); i++) {
    if (HASHISZERO(neighbors[i])) {
      if (debugmsg) D("neighbors[%d] is zero",i);
      continue;
    }
//剔除可能的重复hashBox (搜索半径>5000KM时可能出现)
    if (last_processed &&
      neighbors[i].bits == neighbors[last_processed].bits &&
      neighbors[i].step == neighbors[last_processed].step)
    {
      continue;
    }
//搜索hashBox中满足条件的对象  
    count += membersOfGeoHashBox(zobj, neighbors[i], ga, lon, lat, radius);
    last_processed = i;
  }
  return count;
}
int membersOfGeoHashBox(robj *zobj, GeoHashBits hash, geoArray *ga, double lon, double lat, double radius) {
//获取hashBox内的最大、最小geohash值(52位)
  GeoHashFix52Bits min, max;
  scoresOfGeoHashBox(hash,&min,&max);
//根据最大、最小geohash值筛选zobj集合中满足条件的点
  return geoGetPointsInRange(zobj, min, max, lon, lat, radius, ga);
}
int geoGetPointsInRange(robj *zobj, double min, double max, double lon, double lat, double radius, geoArray *ga) {
//搜索Range的参数边界设置(即9个hashBox其中一个的边界范围)
  zrangespec range = { .min = min, .max = max, .minex = 0, .maxex = 1 };
  size_t origincount = ga->used;
  sds member;
//搜索集合zobj可能有ZIPLIST和SKIPLIST两种编码方式,这里以SKIPLIST为例,逻辑是一样的
  if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
    ……
  } else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
    zset *zs = zobj->ptr;
    zskiplist *zsl = zs->zsl;
    zskiplistnode *ln;
//获取在hashBox范围内的首个元素(跳表数据结构,效率可比拟于二叉查找树),没有则返0
    if ((ln = zslFirstInRange(zsl, &range)) == NULL) {
      
      return 0;
    }
//从首个元素开始遍历集合
    while (ln) {
      sds ele = ln->ele;
//遍历元素超出range范围则break
      
      if (!zslValueLteMax(ln->score, &range))
        break;
//元素校验(计算元素与中心点的距离)
      ele = sdsdup(ele);
      if (geoAppendIfWithinRadius(ga,lon,lat,radius,ln->score,ele)
        == C_ERR) sdsfree(ele);
      ln = ln->level[0].forward;
    }
  }
  return ga->used - origincount;
}
int geoAppendIfWithinRadius(geoArray *ga, double lon, double lat, double radius, double score, sds member) {
  double distance, xy[2];
//解码错误, 返回error
  if (!decodeGeohash(score,xy)) return C_ERR; 
//最终距离校验(计算球面距离distance看是否小于radius)
  if (!geohashGetDistanceIfInRadiusWGS84(lon,lat, xy[0], xy[1],
                      radius, &distance))
  {
    return C_ERR;
  }
//构建并返回满足条件的元素
  geoPoint *gp = geoArrayAppend(ga);
  gp->longitude = xy[0];
  gp->latitude = xy[1];
  gp->dist = distance;
  gp->member = member;
  gp->score = score;
  return C_OK;
}

算法小结

抛开众多可选参数不谈,简单总结下GEORADIUS命令是怎么利用geohash获取目标位置对象的:

1、参数提取和校验;

2、利用中心点和输入半径计算待查区域范围。这个范围参数包括满足条件的最高的geohash网格等级(精度) 以及 对应的能够覆盖目标区域的九宫格位置;(后续会有详细说明)

3、对九宫格进行遍历,根据每个geohash网格的范围框选出位置对象。进一步找出与中心点距离小于输入半径的对象,进行返回。

通过如下两张图在对算法进行简单的演示:

Redis如何实现“附近的人”功能

令左图的中心为搜索中心,绿色圆形区域为目标区域,所有点为待搜索的位置对象,红色点则为满足条件的位置对象。

在实际搜索时,首先会根据搜索半径计算geohash网格等级(即右图中网格大小等级),并确定九宫格位置(即红色九宫格位置信息);再依次查找计算九宫格中的点(蓝点和红点)与中心点的距离,最终筛选出距离范围内的点(红点)。

算法分析

为什么要用这种算法策略进行查询,或者说这种策略的优势在哪,

为什么要找到满足条件的最高的geohash网格等级?为什么用九宫格? 这其实是一个问题,本质上是对所有的元素对象进行了一次初步筛选。 在多层geohash网格中,每个低等级的geohash网格都是由4个高一级的网格拼接而成(如图)。

Redis如何实现“附近的人”功能

换句话说,geohash网格等级越高,所覆盖的地理位置范围就越小。 当我们根据输入半径和中心点位置计算出的能够覆盖目标区域的最高等级的九宫格(网格)时,就已经对九宫格外的元素进行了筛除。 这里之所以使用九宫格,而不用单个网格,主要原因还是为了避免边界情况,尽可能缩小查询区域范围。试想以0经纬度为中心,就算查1米范围,单个网格覆盖的话也得查整个地球区域。而向四周八个方向扩展一圈可有效避免这个问题。

如何通过geohash网格的范围框选出元素对象?效率如何?

首先在每个geohash网格中的geohash值都是连续的,有固定范围。所以只要找出有序集合中,处在该范围的位置对象即可。以下是有序集合的跳表数据结构:

Redis如何实现“附近的人”功能

其拥有类似二叉查找树的查询效率,操作平均时间复杂性为O(log(N))。且最底层的所有元素都以链表的形式按序排列。所以在查询时,只要找到集合中处在目标geohash网格中的第一个值,后续依次对比即可,不用多次查找。 九宫格不能一起查,要一个个遍历的原因也在于九宫格各网格对应的geohash值不具有连续性。只有连续了,查询效率才会高,不然要多做许多距离运算。

综上,从源码角度解析了Redis Geo模块中 “增(GEOADD)” 和 “查(GEORADIUS)” 的详细过程。并可推算出Redis中GEORADIUS查找附近的人功能,时间复杂度为:O(N+log(M)),其中N为指定半径范围内的位置元素数量,而M则是被九宫格圈住计算距离的元素的数量。结合Redis本身基于内存的存储特性,在实际使用过程中有非常高的运行效率。

感谢各位的阅读!关于“Redis如何实现“附近的人”功能”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

您可能感兴趣的文档:

--结束END--

本文标题: Redis如何实现“附近的人”功能

本文链接: https://www.lsjlt.com/news/55705.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Redis如何实现“附近的人”功能
    这篇文章给大家分享的是有关Redis如何实现“附近的人”功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。针对“附近的人”这一位置服务领域的应用场景,常见的可使用PG、MySQL...
    99+
    2022-10-18
  • 使用redis实现附近的人功能
    目录前言工具一、测试数据二、基本命令三、javaApi前言 Redis自3.2版本开始提供了GEO(geograph)功能,支持地理位置相关操作,以实现诸如附近的人这类依赖于地理位置...
    99+
    2022-11-12
  • 微服务 SpringBoot 整合 Redis GEO 实现附近商户功能
    文章目录 ⛄引言♨️广播站一、Redis GEO 数据结构用法⛅GEO基本语法、指令⚡使用GEO存储经纬度、查询距离 二、SpringBoot 整合Redis 导入 店铺数据 到GEO三、...
    99+
    2023-09-09
    redis 微服务 spring boot java 内存调优
  • Android仿QQ附近的人搜索展示功能
     1.概述 老规矩,先上图 原装货(就不录制gif了,大家可以自己在Q群助手开启共享地理位置,返回群聊天页面就看到看到附近的人): 看起来还是挺像的吧。 ...
    99+
    2022-06-06
    展示 Android
  • 怎么使用Java+MySQL实现附近功能
    小编给大家分享一下怎么使用Java+MySQL实现附近功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!前言在移动互联网广泛发展的今天,APP开发成为许多企业进入...
    99+
    2023-05-30
    java mysql
  • Redis实现附近商铺的项目实战
    目录一、GEO数据结构1、入门2、练习二、附加商户搜索1、先批量导入商户坐标2、实现附近商户功能一、GEO数据结构 1、入门 GEO是Geolocation的缩写,代表地理坐标。Redis3.2中加入对GEO的支持,允许...
    99+
    2023-01-29
    Redis附近商铺 Redis附近
  • Android实现微信自动向附近的人打招呼(AccessibilityService)
    学习功能强大的AccessibilityService!!! 以下是本人根据自动抢红包的实现思路敲的用于微信自动向附近的人打招呼的核心代码 public class Aut...
    99+
    2022-06-06
    自动 Android
  • Elasticsearches通过坐标位置实现对附近人的搜索
    目录一 创建mapping二 导入数据三 查询3.1根据给定两个点组成的矩形,查询矩形内的点3.2根据给定的多个点组成的多边形,查询范围内的点3.3查询给定1000KM距离范围内的点...
    99+
    2022-11-13
  • Redis实现多人多聊天室功能
    本文为大家分享了Redis支持多人多聊天室功能的设计代码,供大家参考,具体内容如下 设计原理 左边的一个数据域,代表两个聊天室,聊天室id分别是827,729 在聊天室827里,有2个人,分别是jaso...
    99+
    2022-06-04
    多人多 聊天室 功能
  • 使用Python实现简单的人脸识别功能(附源码)
    目录前言一、首先二、接下来1.对照人脸获取2. 通过算法建立对照模型3.识别前言 今天,我们用Python实现简单的人脸识别技术! Python里,简单的人脸识别有很多种方法可以实现...
    99+
    2022-11-12
  • Redis如何实现MongoDB的getlasterror功能
    这篇文章主要为大家展示了“Redis如何实现MongoDB的getlasterror功能”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Redis如何实现Mong...
    99+
    2022-10-18
  • 如何通过Vue实现@人的功能
    本文采用vue,同时增加鼠标点击事件和一些页面小优化 基本结构 新建一个sandBox.vue文件编写功能的基本结构 <div class="content">...
    99+
    2022-11-12
  • JavaScript中如何实现附件预览功能
    这篇文章给大家分享的是有关JavaScript中如何实现附件预览功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。由于公司的EMP影像平台比较繁琐,还需要下载才能够能够进行图片的...
    99+
    2022-10-19
  • Redis如何实现聊天室功能?
    今天小编就为大家带来一篇介绍Redis实现聊天室功能的文章。小编觉得挺实用的,为此分享给大家做个参考。一起跟随小编过来看看吧。首先,来介绍下关于pub/sub的几个命令。发布消息publish channe...
    99+
    2022-10-18
  • QT实战之打开最近图片功能的实现
    目录一、项目介绍二、项目基本配置三、UI界面设置四、主程序实现4.1 mainwindow.h头文件4.2 mainwindow.cpp源文件五、效果演示一、项目介绍 本文介绍利用Q...
    99+
    2022-11-13
  • QT实战之打开最近文档功能的实现
    目录一、项目介绍二、项目基本配置三、UI界面设置四、主程序实现4.1 mainwindow.h头文件4.2 mainwindow.cpp源文件4.3 main.cpp五、效果演示一、...
    99+
    2022-11-13
  • Java如何实现带附件的邮件发送功能
    这篇文章主要讲解了Java如何实现带附件的邮件发送功能,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。需要导入mail.jar、activation.jar这两个邮件发送的jar包,可在网上搜索并下载需要设置相关...
    99+
    2023-05-31
    java ava
  • 微信小程序中如何实现搜索附近的iBeacon设备
    这篇文章主要为大家展示了微信小程序中如何实现搜索附近的iBeacon设备,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带大家一起来研究并学习一下“微信小程序中如何实现搜索附近的iBeacon设备”这篇文章吧。wx.start...
    99+
    2023-06-26
  • Redis如何实现消息队列功能
    Redis如何实现消息队列功能随着互联网的发展,消息队列在分布式系统中变得越来越重要。消息队列允许不同的应用程序之间通过异步通信来传递和处理消息,提高了系统的可伸缩性和可靠性。Redis作为一款快速、可靠、灵活的内存数据库,也可以用来实现消...
    99+
    2023-11-07
    redis 实现 消息队列
  • redis如何实现收藏功能设计
    Redis可以通过使用有序集合来实现收藏功能的设计。具体步骤如下:1. 创建两个有序集合,一个用于存储用户收藏的内容,另一个用于存储...
    99+
    2023-08-31
    redis
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作