Redis场景应用实例

Redis的相关知识点和需要注意的问题我们都已经梳理过了,关键还是需要运用到实际的工作中才能达到学以致用,下面我们将整理一个实际应用的场景,并且集合Redis来实现其需求。

目前公司有十万员工,分成500个部门,公司为员工制定了每日9点前和18点后网上签到的制度,签到之后可以及时查看自身签到状态,主管可以及时收到下属员工的签到状态,一整天未签到的员工自动补充旷工

以上为场景;请用java+redis+队列+mysql实现此功能

分析该需求,首先10w的员工签到,这个涉及到高并发的场景,并且主管还需要及时收到下属员工的签到状态,这个需要异步通知的功能,并且一整天未签到的员工自动补充旷工,这个需要一个定时任务来实现

综上所述我们为了实现其功能最少需要高并发签到,异步通知以及定时任务这三个技能,明白了其所需要使用到的技术,下面我们来一个个的剖析,并且实现这样的功能。

高并发来实现签到功能

为了实现高并发,题目中已经给出了我们需要使用redis来实现,这个没得选,但是我们还是需要分析下是单机版还是Redis集群来实现这样的功能。

单机还是集群?

10w员工,按照二八定律分析来说大概同时有2w的签到,也就是写请求(二八定律真乃神定律,在现实生活中随处可见),单机版本的Redis大概能支持10w左右的QPS(这个数值有波动,主要跟服务器的性能有关系,内存读写速度快的,这个数值还会更大点),所以我们这个单机版的Redis就能实现这样的功能,如果是员工是100w的话,我们就需要搭建Redis服务集群,最好还是能做到读写分离,这样还能做到横向扩容。

数据结构很重要!!

一个适用的数据结构能优化代码逻辑,并且减少操作时间复杂度,优化服务响应速率,提升客户使用度,所以数据结构十分的重要。

  1. 首先确定使用redis的数据类型

学过Java的朋友应该都知道Java中的Map的理想操作时间复杂度是O(1),也就是说对于内存来说,访问任何地址的时间是一样的,即时间极短,相当于可以同时访问到所有地址,那么这里redis的hash数据类型和Java的Map是类似的,所以我们选用hash类型来实现所有员工在Redis中的数据存储

  1. 继续优化hash的数据结构

看到这里有的朋友可能会考虑,将10w的员工的信息都存放在Redis中,就需要10w个key(map),No,No,不是这样的!为什么不这样,我们来分析下。

还是跟Map的类型有关,如果10w个map存储在redis中,需要消耗一定的内存,并且数据越大,内存查询的速度也就越慢,所以我们的着眼点应该是按照部门来分别存储,这样查询的时候也可以根据部门来减少查询到次数,所以我们第一层的数据结构应该是以部门ID+常量+签到日期为key的map,这样做的好处有两个:

  • 每个人都是归属部门的,所以先根据部门来缩小查找的范围,减少查询遍历的次数:500+2000=2500,也就是说我们定位一个人最大遍历2500次就够了,而如果是直接查询个人的话,最大可能遍历10w次。
  • Redis中存放500个map比存放10w个map来的小的多,减少了redis的数据存储内存的消耗

接着,我们再来分析下value的存储什么?

我们的需求是员工进行签到,所以我们的value值中必须要包含是否签到的相关信息,这里我们还可以扩展下,需求要求是上班前和下班后都进行签到,需要区分签到的类型,所以我们还可以添加一个常量来进行签到类型区分,其次是谁签到的,说到这里,我想这个数据结构已经很清晰了。

是的还是使用hash结构来存放人员的信息,其中key值最好是人员的id,而value值可以是签到的状态

  1. 数据结构的确定
    至此,经过我们的分析,我们确定了Redis中签到的数据结构,使用Java的数据结构来表达:
    // 外围的Key是String类型: 主要存放部门的id+常量+签到日期
    // 外围的Value是Map类型:主要存放该部门的人员的信息
    // 里层的Key是String类型: 主要存放人员的ID
    // 里层的key也是String类型(这里也可以修改为List类型): 主要存放签到的状态
    Map<String,Map<String,String>>

业务流程的实现

  1. 初始化数据

既然签到的map数据结构已经确定了,那么我们该怎么来使用这个数据结构来实现我们的业务呢?

这里提供一个方案,我们可以提前将部门的map的数据给初始化,有两个原因:

  • 部门和人员的数据一般变动不大,所以可以先初始化,节省时间,到时直接从Redis中取就可以了
  • 避免签到的时候才来生成部门签到map,主要是为了避免签到高并发时,造成数据覆盖现象,导致签到数据不正确

这里的部门签到map(暂时这么称呼),其有效期应该设置为永远,避免数据失效!

  1. 签到

用户登录系统后,我们会在redis中生成用户的基本信息,这里主要是用户的人员ID和所在部门的ID。

  • 用户签到的时候,将个人信息写入到redis,主要是为了用户查看其基本信息,包括签到的状态信息
  • 根据员工ID和部门ID到部门签到map中获取人员的相关信息,并且更新签到状态。这里最好添加锁,防止被其他员工取到产生竞态,等部门签到map中的个人签到状态更新成功之后,释放锁,并且更新redis中个人信息中的签到状态
  • 将签到相关信息放入队列中

上述的签到流程操作,可以及时的让用户查看到自己的签到情况,即使高并发的情况下也不影响系统的响应流畅度

  1. 通知主管

用户签到之后,就将签到的信息发送到队列,通过队列来异步通知主管,这里可以使用RabbitMQ来实现消息的发送通知,主要是考虑RabbitMQ的消息的安全和消息消费失败后,可以使用死信队列来实现重发,确保消息的准确和安全性。

  1. 定时数据持久化

开启一个定时任务,将部门签到map提取出来,然后循环遍历,将人员签到的信息持久化到数据库,对于持久化失败的数据,可以写入到日志中,展示给相关人员查看。将一整天都未签到的人员置为旷工。

数据持久化后,可以删除当天的部门签到map,同时初始化明天需要用到的部门签到map

可以是用流程图展示如下:

[图片上传失败...(image-7d95d9-1561206189155)]

至此,我们的整个业务流程就很清晰了,对应的代码实现也就很容易了

总结

在对人员签到的分析设计已经结束了,不过我们就其中的几个问题需要讨论下

为了实现上述的功能,redis中最小的key值是多少?

我们上面设计中 redis中的key是500个? 那能不能再次缩小呢? 其实是可以的,就是在外面再加一层map,这样保存到redis中就一个key键值了,如果这样设计的话,那其实没有什么意义,还是需要查找到对应的部门,再查找到人员,这样反而增加了一步查询,还不如不加,而且如果只有一个key值的话,那么用户签到的时候需要加锁,就将这个key添加了锁,这样话并发量就不是很大了,所有的用户都要等该用户签到完成后再进行其拿到,从业务角度来看就是将10w员工的签到串行了,我们上面设计的500个key,对不不同部门的人员签到是不影响的,从业务角度来说,不同部门是可以同时签到的,而且不影响数据,提高了效率。

为什么需要吧签到的信息发到员工的信息里,还要保存到部门签到map中?

我们上面的设计中 redis的部门签到map中已经存放了人员的签到信息,为什么还要在个人信息中存放签到信息呢? 主要是为了需求中用户可以随时查看自己的签到状态。

这里有的朋友可能就疑问了,部门签到map中不是已经存在了么,这里主要是为了人员查看的效率考虑的,如果存放在部门签到map中,那么每次查看一次都需要从部门签到map中提取出来个人信息才能查看,这样会影响查看效率。

如果基于redis实现加锁和释放锁功能,如何考虑其中的锁释放问题?

加锁的功能其实也可以由redis来实现,我们可以在签到时,对这个部门ID+加锁常量+签到日期,在redis中新增一个key,如果同部门的其他用户也来签到时,先查看是否存在部门ID+加锁常量+签到日期的key,如果存在则循环等待一段时间再请求,相当于给当前签到用户添加了锁,等这个用户签到成功后,再删除这个key。

上面就是简单的加锁的功能,这样需要考虑释放锁的问题,如果加锁成功了,程序在处理业务时程序异常,没有正常的释放锁,这样就会造成其他的人员获取不到锁,无法进行业务操作,解决这个问题,我们首先需要考虑不管业务是否成功,我们都需要释放锁,这样至少不会对其他的人员签到造成影响。

那么该如何实现这样能,其实redis能很简单的实现,就是给这个key添加失效时间,这样只要到失效时间,这个key就会被删除,也就相当于释放了锁。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容