点评项目概览

在这里插入图片描述
在这里插入图片描述
项目功能
查看点评(热评)、发布点评、点赞
关注、查询关注的人发的帖子、查看好友共同关注
分类浏览店铺、查看附近的店铺
个人信息查看和管理

技术栈
后端
Spring 相关:Spring Boot 2.x、Spring MVC
数据存储层:MySQL:存储数据、MyBatis Plus:数据访问框架
Redis 相关:spring-data-redis:操作 Redis、Lettuce:操作 Redis 的高级客户端、Apache Commons Pool:用于实现 Redis 连接池、Redisson:基于 Redis 的分布式数据网格
工具库:HuTool:工具库合集、Lombok:注解式代码生成工具
前端
原生 HTML、CSS、JS 三件套、Vue 2、Element UI 组件库、axios 请求库

详细参考https://blog.csdn.net/weixin_45033015/article/details/127545710

redis类型:string,hash,list:有序类似双链表,set,sortedset:比set多一个分数,geo,bitmap,hyperlog
jetis:线程不安全
springDataRedis使用
特点:整合了 Lettuce和jedis,提供 redisTemplate 封装形成统一API 底层来操作不同客户端,支持 基于JDK,JSON,String的数据序列化(将对象变成 字符串 或 字节)和反序列化
方案一 自动序列化:
使用自定义的RedisTemplate K使用string序列化 V使用json序列化,多一个类信息占空间
方式二 :手动序列化
与方式一不同 ,V也要采用使用String序列化,但不用自己制定,spring专门提供了将K_V都转为 String的 StringRedisTemplate

session 共享问题 :tomcat可能以集群分布,不同的tomcat有都有自己的session ,但tomcat之前无法共享。使用redis 替代session,将由jvm内存中储存的数据改为放在redis中,有cookie携带的sessionId改为从localStore取出携带的redis的key。采用hutool的uuid作为token。当前登录用户信息放threadlocal里。

拦截器一:一切,如果有token就放在threadlocal然后刷新有效期,二:要登录的:threadlocal有放行

更新店铺id
更新数据库缓存:改数据库把缓存删了然后不要写缓存,等读再写
若先删除缓存,可能存在当 把缓存删除后,数据库还未还未更新完,此时由一个请求查找不到缓存,读取了数据库旧值,并将旧值写入缓存。
若先操作数据库,在删除缓存:新线程在查询数据缓存未命中时,查询数据库,正准备将数据写入缓存,这时一个线程将数据修改并删除了缓存,而写入缓存的是旧数据。

查店铺id
缓存穿透:如果恶意频繁发送数据库不存在的数据,大量请求穿透缓存直接到达数据库,会搞垮数据库。缓存空对象或者布隆过滤(哈希)
缓存雪崩:同一时间,大量请求无法使用缓存(key集体过期,缓存服务器宕机),像雪崩一样冲向数据库
缓存击穿:热点的key过期,导致一瞬间大量访问该key的请求打到数据库,在重建长时间里,大量请求透过,多次进行缓存重建
法一:一个请求拿到互斥锁后,独自进行创建缓存。在重建缓存完成之前,其他线程只能等待一会后重复以上步骤
法二:其他线程不用等,逻辑过期的旧数据直接返回。加逻辑过期就是不设置ttl,在存储的数据字段里手动添加过期的时间。当一个线程查看到逻辑过期了,就会先加锁然后开一个新线程重建自己返回旧数据

全局唯一id放优惠券:时间戳32位+redis自增32位
查询库存和扣除库存之间,有多个线程同时查询满足库存条件,创建了订单,导致超卖问题
悲观锁:认为线程安全问题一定会发生,在操作数据之前先获取锁,确保线程串行执行
乐观锁:认为线程安全问题不一定会发生,因此不加锁,在更新数据时再查一次去判断有没有对数据做了修改。如果没有修改则认为是安全的。成功率低,不用相等只要第二次查大于0即可

一人一单问题:先查询再操作数据库,中间有间隔,再一次导致一人多单;一人多单的原因是一个用户同时发起大量请求。只能加悲观锁因为创建订单不像前一个根据库存判断。注意synchronize先于提交事务释放所以整个方法锁住还需要换成动态代理对象。集群导致jvm各自有锁出现一人多单换成redis分布式锁。
超时释放导致误删锁问题:线程1 还没有遇到阻塞,导致没有执行完锁超时释放被线程2获取,而线程1执行完后,删除了不是自己的锁 (因为同用户锁的key相同),导致正在执行的线程2没有了锁的保护。解决方法,在创建线程时,放入自己线程的标识,在删除时进行判断是否是自己的线程,防止误删。需要在value中放入自己的线程编号。
判断是自己的锁后再删除锁应用lua脚本保证原子性。不然自己突然被阻塞导致锁超时那就释放了下一个锁了。

缺少的功能:不可重入:同一个线程多次尝试获取通一把锁。例如 A方法获取锁 ,要执行B方法,而B方法中也要获取锁才能执行。同一个线程要获取两次锁 ,由于setNx的互斥性,即使是同一个线程,在不释放的前提下也不能再次获取 。不可重试: 锁被占用,会进行阻塞重试。主从一致问题:读写一致问题,在集群条件下,锁在多个节点同步过程可能出现延迟,或在同步过程宕机导致锁丢失。

redission:自定义获取锁的方式是采用 setNx lock thread, Redission 采用的是 setNx lock thread 1这种hash结构,key 是锁的标识 filed是线程的标识,value是获取的次数。多次查询判断和数据操作不是同时进行,为防止线程安全问题,保证原子性,使用lua脚本。redission并没有一味的循环尝试,而是根据自己的剩余的时间和锁:第一次获取,若失败,则在自己剩余的时间里,监听锁的释放时间,若监听到锁的释放却没有争取到,则开始再次进行订阅,在自己剩余的时间里,进行循环。锁释放原理:在获取锁时,若传递锁过期释放时间,则过期就释放。若不传递,采用看门狗方式,初始为30s,每隔10s刷新过期时间,重新设置10s,即使锁重入也是如此。在释放锁时取消刷新。
主从一致原理:当redis以主从模式,读写分离下,主节点负责写,然后将数据同步给从节点,从节点负责读。如果创建锁后,在同步给从节点一瞬间主节点宕机,将导致锁的数据的丢失,其他线程还能创建锁,导致并发安全问题。redission 解决方案:设置三个及以上的主节点,同时向各个节点保存锁的标识。只要有一个节点没来得及同步就宕机,会导致获取锁失败。

不可重入的 Redis 分布式锁
原理:利用 setnx 的互斥性、ex 避免死锁、释放锁时判断线程标识避免误删。
缺陷:不可重入、无法重试、锁超时有自动释放的风险。
可重入的 Redis 分布式锁
原理:利用 Hash 结构,记录线程标识和重入次数、利用 WatchDog 延续锁的超时时间、利用信号量控制锁重试等待。
缺陷:Redis 宕机引起锁失效问题。
Redisson 分布式锁原理
可重入:利用 Hash 结构记录线程标识和重入次数。
可重试:利用信号量 和 PubSub 功能实现等待、唤醒、获取锁失败的重试机制。
超时续约:利用 WatchDog,每隔一段时间(releaseTime / 3),重置超时时间
Redisson 的 MultiLock
原理:多个独立的 Redis 节点,必须在所有节点都获取重入锁,才算获取所成功。
缺陷:运维成本高、实现复杂。

异步秒杀:查券查订单减库存下单lua返回给用户然后订单放在阻塞队列,有一个消费者负责读队列写入数据库。
队列问题:内存限制 若不加以限制,可能导致内存溢出;若限制,队列中满了可能会丢失数据。数据安全问题:基于内存储存,如果突然宕机,使得任务丢失。从队列取出后,处理发生异常,导致任务丢失。
Stream:redis5.0 引入的新数据类型,一个功能完善的消息队列,存在漏读风险。
消息可回溯,stream是redis的一种数据结构,可以进行持久化。可以阻塞获取。添加组机制后优点:同组消费者进行争抢消费,且只能消费一次 确保消息处理效率且防止重复处理。采用消息标识,不会漏读消息。采用消息确认,保证消息在被成功处理前不会丢。
只支持消费者的确认(发动Ack),而没有生产者确认机制。在生产者向消息队列中发送消息这一过程,也有可能出错。
替换java的阻塞队列。
消息标示:消费者组会维护一个标示,记录最后一个被处理的消息,即使消费者宕机重启,还会从标示之后读取消息,确保每一个消息都会被消费。(解决漏读问题)
消息确认:消费者获取消息后,消息处于 pending 状态,并存入一个 pending-list。当处理完成后需要通过 XACK 命令来确认消息,标记消息为已处理,才会从 pending-list 中移除。(解决消息丢失问题)

使用redis 使用set集合(利用不可重复特性,与前面一人一单相似),根据博客编号作为key,value存放所有给此博文点赞的用户id,这里持久化了没放在数据库。数据库博文只记录点赞数。
但要查前五个点赞的所以换成sortedset存时间戳。
共同关注:利用set的交集功能。
滚动分页:按下标分的话因为新来的占前面会导致重复读取。用sortedset记录时间戳,每次从上一个最后时间戳查。
推模式下发布博文投到粉丝的sortedset。

附近商户:geo是一个sortedset
用户签到:bitmap一个月一个key
uv即 Unique Visitor 独立访客量。即每天每个人无论访问多少次该网站,都只会被记录一次
pv即 Page View 页面访问量:只要有一访问,无论是否是一个人多次访问,,只要访问一次就记录一次。用户衡量网站流量
hyperLoglog 数据结构:一种概率统计算法,基于String数据结构实现 。用户确定数据量非常大的集合基数,而不需要存储其所有值。最大亮点无论多么大的数据量,内存占用永远小于16K,但是有小于0.81%误差

redis缓存多测几次是有提升的大概从500ms到50ms
hyperlog:1654464-1650832,set:1691384-1651048,39k到3k

stream队列异步秒杀测试
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值