前言

点赞其实是一个很有意思的功能。基本的设计思路有大致两种, 一种自然是用mysql等

数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回mysql等。

直接写入Mysql

直接写入Mysql是最简单的做法。

做两个表即可,

  • post_like

    记录文章被赞的次数,已有多少人赞过这种数据就可以直接从表中查到;

  • user_like_post

    记录用户赞过了哪些文章, 当打开文章列表时,显示的有没有赞过的数据就在这里面;

缺点

  • 数据库读写压力大

    热门文章会有很多用户点赞,甚至是短时间内被大量点赞, 直接操作数据库从长久来看不是很理想的做法。

redis存储随后批量刷回数据库

redis主要的特点就是快, 毕竟主要数据都在内存嘛;

另外为啥我选择redis而不是memcache的主要原因在于redis支持更多的数据类型, 例如hash, set, zset等。

下面具体的会用到这几个类型。

优点

  • 性能高

  • 缓解数据库读写压力

    其实我更多的在于缓解写压力, 真的读压力, 通过mysql主从甚至通过加入redis对热点数据做缓存都可以解决,

    写压力对于前面的方案确实是不大好使。

缺点

  • 开发复杂

    这个比直接写mysql的方案要复杂很多, 需要考虑的地方也很多;

  • 不能保证数据安全性

    redis挂掉的时候会丢失数据, 同时不及时同步redis中的数据, 可能会在redis内存置换的时候被淘汰掉;

    不过对于我们点赞而已, 稍微丢失一点数据问题不大;

具体设计

Mysql设计

这一块和写入写mysql是一样的,毕竟是要落地存储的。

所以还是同样的需要post_like, user_like_post这两表存储文章被点赞的个数(等统计), 用户对那些文章点了赞(取消赞)。

这两表分别通过post_id, user_id进行关联。

redis设计部分:

post_set

在redis中弄一个set存放所有被点赞的文章

post_user_like_set_{$post_id}

对每个post以post_id作为key, 搞一个set存放所有对该post点赞的用户;

post_user_like_{$post_id}_{$user_id}

将每个用户对每个post的点赞情况放到一个hash里面去, hash的字段就

随意跟进需求来处理就行了。

为啥用hash

只所以用hash是因为完全可以用hash来存储一个点赞的对象, 对应数据库的

一行记录。

当然有同学会说用key, value也可以, 将所有的数据序列化(json_encode等)

后全部放到value里面去。 反复序列化也是一个很大的开销不是, hash可以很

方便的修改某个字段, 而序列化和反序列化的操作。

post_{$post_id}_counter

对每个post维护一个计数器, 用来记录当前在redis中的点赞数,

这里我们只用counter记录尚未同步到mysql中的点赞数(可以为负), 每次

刷回mysql中时将counter中的数据和数据库已有的赞数相加即可。

用户点赞/取消赞

获取user_id, post_id, 查询该用户是否已经点过赞, 已点过则不允许再次点赞,

或者设计为前端允许用户点, 只是后台不重复计算;

这里需要注意的是用户点赞的记录可能在数据库中, 也可能在缓存中, 所以查询的时候

缓存和数据库都要查询, 缓存没有再查询数据库。

将用户的点赞/取消赞的情况记录在redis中, 具体为:

  • 写入post_set

    将post_id写入post_set

  • 写入post_user_like_set_{$post_id}

    将user_id写入post_user_like_set_{$post_id}

  • 写入post_user_like_{$post_id}_{$user_id}

    将用户点赞数据, 例如赞状态, post_id, user_id, ctime(操作时间), mtime(修改时间)写入post_user_like_{$post_id}_{$user_id}中

  • 更新post_{$post_id}_counter

    更新post_{$post_id}_counter, 这里的更新稍晚复杂一点, 需要和前面一样先获取当前用户是否对这个post点过赞

    如果点过, 并且本次是取消赞, counter减一, 如果没点过, 本次是点赞, counter加一。

    如果原来是取消赞的情况, 本次是点赞, counter加一。

同步刷回数据库

  • 循环从post_set中pop出来一个post_id至到空

    • 根据{$post_id}, 每次从post_user_like_set_{$post_id}中pop出来一个user_id直到空

      • 根据post_id, user_id, 直接获取对应的hash表的内容(post_user_like_{$post_id}_{$user_id}

      • 将hash表中的数据写入user_like_post表中

      • 将post_{$post_id}_counter中的数据和post_like中的数据相加, 将结果写入到post_like表中

页面展示

  • 查询用户点赞情况
    前面已经说过, 需要同时查询redis和mysql

  • 查询post点赞统计

    同样需要查询redis中的post_{$post_id}_counter和mysql的post_like表, 并将两者相加

    得到的结果才是正确的结果

总结

    • 解决了mysql读写的问题

    • 但没有针对用户量较大的场景考虑分表的设计, 可以考虑针对user_id或者post_id进行分表

http://www.furion.info/808.html?utm_source=tuicool&utm_medium=referral

基于redis的点赞功能设计的更多相关文章

  1. [转载] 基于Redis实现分布式消息队列

    转载自http://www.linuxidc.com/Linux/2015-05/117661.htm 1.为什么需要消息队列?当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消 ...

  2. 基于redis的处理session的方法

    一个基于redis的处理session的方法,如下. <?php class Session_custom { private $redis; // redis实例 private $prefi ...

  3. 基于redis 实现分布式锁的方案

    在电商项目中,经常有秒杀这样的活动促销,在并发访问下,很容易出现上述问题.如果在库存操作上,加锁就可以避免库存卖超的问题.分布式锁使分布式系统之间同步访问共享资源的一种方式 基于redis实现分布式锁 ...

  4. Tomcat7基于Redis的Session共享实战二

    目前,为了使web能适应大规模的访问,需要实现应用的集群部署.集群最有效的方案就是负载均衡,而实现负载均衡用户每一个请求都有可能被分配到不固定的服务器上,这样我们首先要解决session的统一来保证无 ...

  5. 基于redis实现可靠的分布式锁

    什么是锁 今天要谈的是如何在分布式环境下实现一个全局锁,在开始之前先说说非分布式下的锁: 单机 – 单进程程序使用互斥锁mutex,解决多个线程之间的同步问题 单机 – 多进程程序使用信号量sem,解 ...

  6. 基于redis分布式缓存实现(新浪微博案例)

    第一:Redis 是什么? Redis是基于内存.可持久化的日志型.Key-Value数据库 高性能存储系统,并提供多种语言的API. 第二:出现背景 数据结构(Data Structure)需求越来 ...

  7. .NET基于Redis缓存实现单点登录SSO的解决方案[转]

    一.基本概念 最近公司的多个业务系统要统一整合使用同一个登录,这就是我们耳熟能详的单点登录,现在就NET基于Redis缓存实现单点登录做一个简单的分享. 单点登录(Single Sign On),简称 ...

  8. 基于redis排行榜的实战总结

    前言: 之前写过排行榜的设计和实现, 不同需求其背后的架构和设计模型也不一样. 平台差异, 有的立足于游戏平台, 为多个应用提供服务, 有的仅限于单个游戏.排名范围差异, 有的面向全局排名, 有的只做 ...

  9. .NET基于Redis缓存实现单点登录SSO的解决方案

    一.基本概念 最近公司的多个业务系统要统一整合使用同一个登录,这就是我们耳熟能详的单点登录,现在就NET基于Redis缓存实现单点登录做一个简单的分享. 单点登录(Single Sign On),简称 ...

随机推荐

  1. Maven的POM.xml配置大全

    <?xml version="1.0" encoding="utf-8"?> <project xmlns="http://mave ...

  2. The specified module could not be found

    打开IIS 信息服务,在左侧找到自己的计算机,点右键,选择属性,在主属性中选编辑,打开“目录安全性”选项卡,单击“匿名访问和验证控制”里的“编辑”按钮,在弹出的对话框中确保只选中了“匿名访问”和“集成 ...

  3. js调用php和php调用js的方法举例

    js调用php和php调用js的方法举例1 JS方式调用PHP文件并取得php中的值 举一个简单的例子来说明: 如在页面a.html中用下面这句调用: <script type="te ...

  4. 企业号查询部门id(改版后)

    1.搜索部门,输入"名称" 2.在后面可以查到部门ID

  5. Feature Access

    在ArcGIS Server中发布支持Feature Access地图服务,你需要知道的几点: 所绘制的mxd地图文件中包含的数据,必须来自企业级数据库链接: mxd中包含的所有图层的数据,必须来自同 ...

  6. JetBrains PyCharm 2016.2.3注册码

    43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...

  7. 【http】四种常见的 POST 提交数据方式

    来源:http://www.cnblogs.com/aaronjs/p/4165049.html HTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS.GET.HEAD.POST.PUT ...

  8. 简单的ADO.NET连接数据小样例

    ADO.NET连接数据库的样例如下: using System; using System.Collections.Generic; using System.ComponentModel; usin ...

  9. 3ds max旋转简化后模型

    简化后的模型无法与原场景直接匹配,因此需要以下步骤: 简化后的模型导入,原点在右上角 旋转后,方法是选中所有模型,右键->旋转 在偏移的x和y各输入180 还有做一些平移,微调 在导入整个she ...

  10. c#_图表之zeGraph

    关于图表控件: http://blog.csdn.net/sgear/article/details/1449025 其中zedGraph的基本方法及属性介绍: http://wenku.baidu. ...