# dianping_project **Repository Path**: SiHuiSheng/hm-dianping ## Basic Information - **Project Name**: dianping_project - **Description**: 点评项目 实现安全登陆、注销登陆 探店、点赞、相互关注、发送点评文章、发放优惠券、秒杀券、抢券、附近商铺等功能。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2024-06-09 - **Last Updated**: 2024-06-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # hm-dianping #### 介绍 点评 #### 软件架构 springboot mybatis redis`` #### 安装教程 1. xxxx 2. xxxx 3. xxxx #### 主要功能 1. 实现根据手机号注册、根据手机号获取验证码进行登陆、手机号密码进行登陆、通过jwt认证对用户访问进行授权、注销登陆。 JWT:用户登陆->获取验证码->验证码校验->手机号存在->根据用户手机号查询用户->生JSON Web Token(header Base64编码.payloadjson进行Base64编码.payloadjson+秘钥(盐值)MD5加密)->将jwt放入请求头中,每次客户发请求都携带jwt进行授权认证。 Redis: ->将用户数据以哈希的数据结构保存到redis,自动生成UUID作为key(token)->每次访问私有资源就拦截请求 Session: ->将用户数据存放到Session中->每次访问私有资源判断拦截请求 JWT:用户访问私有资源->过滤器->判断jwt在redis中是否存在->存在->重定向到登陆页面 ->不存在->验证jwt是否有效->有效,存入ThreadLocal->通过过滤器,获得私有资源。 ->无效,重定向到登录界面 Redis:用户访问私有资源->拦截器->获取请求头中token->存在,存入ThreadLocal->通过拦截,获得私有资源。 ->不存在拦截->重定向到登陆页面 Session:用户访问私有资源->拦截器->获取Session中的数据->存在,存入ThreadLocal->通过拦截,获得私有资源。 ->不存在拦截->重定向到登陆页面 手机号密码登陆->前端利用后端生成的公钥对密码进行加密->将数据发送给后端->后端使用私钥解密,获得明文密码->将明文密码转成MD5->根据手机号、MD5密文查询数据库->存在用户->生成jwt... ->不存在->反馈前端,密码错误 退出登陆->从请求头中获取jwt,计算剩余过期时间->存入redis中,并设置过期时间 2. 缓存店铺的信息 查询店铺信息->查询redis->redis存在返回店铺信息 ->redis不存在->查询数据库->数据库不存在->返回提示信息 ->数据库存在->保存店铺信息到redis,并设置过期时间,并返回数据 店家修改店铺信息->先修改数据库,然后删除缓存(确保数据库与缓存操作的一致性,加入@Transactional开启事务) 缓存穿透:客户请求的数据在缓存和数据库中都不存在,这样缓存就无效了,所有的请求都会到达数据库,需要执行一些sql语句,但是这些sql的执行都是无效的,影响系统性能。 缓存空对象解决缓存穿透:客户端请求->未命中->查询数据库->不存在->保存null到redis,并设置过期时间 (弊端:会造成缓存与数据库的短期不一致,额外的内存消耗) 布隆过滤器解决缓存空对象;将数据通过哈希算法映射到一张bit数组上,当一个数据经过哈希算法后再bit数组上对应位全部是1就说明可能在数据中存在,否则一定不存在,这就是布隆过滤器 客户发起请求->布隆过滤器->通过->查找缓存->存在数据->响应数据 ->不存在数据->查询数据库->存在->将数据存入缓存中,并返回数据 ->不存在->返回提示信息 ->不通过->返回提示信息 缓存雪崩:大量缓存同时失导致这一段时间大量请求到达数据库,解决方案为给不同key的数据添加某一范围内随机大小的过期时间. 缓存击穿:某些热点数据过期,导致同一时间内大量请求到达数据库,且重复重建缓存,给数据库带来了巨大压力。 逻辑过期解决缓存击穿:客户端请求->查询缓存->数据过期->获取互斥锁成功->返回过期数据,开启新线程去写入缓存->写入完成,释放锁。 ->获取互斥锁失败->返回旧数据。 互斥锁解决缓存击穿:客户请求->查询缓存->未命中->获取互斥锁成功->写入缓存,并返回数据 ->获取互斥锁失败->休眠一会,查询缓存->直到查到数据 (互斥锁使用分布式互斥锁,利用redis的setnx) 3. 秒杀业务 不使用锁机制--线程不安全、会导致库存超卖、一人抢多个优惠券 乐观锁解决库存超卖问题--存在成功率低的问题 悲观锁解决库存超卖问题--解决了秒杀成功率低的问题,但是让线程串行执行,效率变低了 分布式锁+消息队列解决库存超卖实现一人一单 (setnx lock thread1, expire lock 10, del key)(set lock thread1 nx ex 10) --用lua脚本实现:库存和一人一单判断、扣减库存、下单、发送消息到队列当中 分布式锁实现一人一单:锁利用 注意:Redis还保证lua脚本以原子方式执行:在执行脚本时,不会执行其他脚本或Redis命令 利用Redisson开源框架解决基于setnx实现的分布式锁存在的不可重入、不可重试的问题 setnx作为分布式锁存在的问题:不可重入、不可重试(尝试获取锁失败就立即返回FALSE,不等待) redisson可重入锁的原理:判断锁是不是被当前线程所拥有、是的话重入次数加1并重置过期时间,释放锁的时候自己就-1并重置有效期,直到重入次数为0就真正的释放锁。可用hash数据结构实现(代替String结构) redisson可重试的原理:释放锁的时候会发布一条释放锁的消息通知,当获取说失败的时候回去订阅释放锁的消息通知,然后等待一段时间判断是否收到释放锁的消息通知,在判断获取锁的结果 消息队列是JVM以外的独立服务,不受JVM内存的限制、有消息确认机制,支持数据持久化 基于Stream的消息队列:xadd xread 4. 点赞:数据结构:set,判断集合是否点赞过,已点赞点赞数-1,从点赞集合中移除当前用户id 点赞排行榜:数据结构zset(sortedset) 因为list不能保证元素的唯一性,set无法排序,而zset可以根据score排序 score:点赞时的时间戳 关注: 数据结构:set(与点赞一样) 共同关注:求取当前用户与访问用户的关注set交集 sinter k1 k2 ... 关注推送:传统的方式(用户根据关注博主的id查询数据库然后按照时间排序) feed流 这里有两种方案:拉取:博主发布博文到自己的发件箱,然后粉丝查看推文的时候就根据关注用户的id查询发件箱(占用空间小,但是用户需要查询多个博主发件箱,效率低) 推送:博主发布博文到粉丝的收件箱,粉丝查询自己的收件箱(占用空间大,不同的粉丝信箱有大量相同的内容,但是查询效率高) 优化:对于普通用户--因为大量用户其实基本不发博文,基本不需要单独设计一个发件箱,因此采用推送的方式。 对于大博主就需要单独设计一个发件箱,以节省空间。 综上:人人都有收件箱,但收件项不存大博主的博文,只存放普通用户的博文,大博主有发件箱:存放大博主的博文--大V的博文属于热点数据可以加一层redis缓存。 附近商户:GEO(zset value-score(x,y坐标)) 店铺类型作为key 用户签到:传统的签到表有用户id、签到日期组成,如果用户很多的话就会使这个表是数据量非常大,可以考虑用一个bit(31)的数据类型字段代替 UV(unique visitor)统计:HyperLogLog 一天内一个用户多次访问只会记录一次,redis中的HyperLogLog是基于string来实现的,单个HLL内存永远小于16kb,但是测量结果有0.81%左右的误差 对于UV统计来说完全可以忽略。HLL适合作为海量数据的统计工作。 3. xxxx #### 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request #### 特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)