项目-Web社区论坛
讲一讲你这个项目
概述
这是一个单体的Web论坛项目,最大的特点是涉及的技术比较多,实现了诸多现实场景下的小功能,诸如:
- 后端验证码生成和校验
- JWT登录认证
- Redis实现点赞、关注、热帖排行和网站数据统计
背景
技术选型上是基于经典的SSM,用Spring Boot支持快速起步,提升开发效率,前端使用Thymeleaf模板引擎
项目的重点是放在了诸多技术的整合,对Spring框架及其生态横向广度与纵向深度的理解,以及Redis和EleasticSearch使用和进一步了解上面
当然项目中值得深入拓展的点也非常多,甚至说整个架构都可以从单体拆分出来
讲一讲登录
登录这方面主要就是 验证码生成校验 和 JWT认证两方面
验证码生成使用的是Google开源的Kaptcha验证码生成工具在后端生成验证码图片,通过Base64算法转成字符串传递给前端,前端还原并把获取到的输入返回给后端验证
用户身份校验使用的是JWT,为每个用户生成token返回并由客户端保管,每次请求头中再携带上这个token
讲一讲JWT
JWT的数据结构是由"."分隔的三个部分组成的字符串,分别是头部、负载和签名
- 头部是描述JWT的元数据
- 负载是存放的用户数据,但是这里不能放私密信息,JWT默认是不加密的,就算加密了放到客户端也不妥当
- 签名是指定一个“密钥”,再加上前两个字段,使用header里面指定的签名算法生成的
JWT的好处和弊端是什么?和Session有什么区别?为什么考虑用JWT而不是Session
相较于Session保存在服务端,JWT的最大优势在于 避免了不同服务器间的跨域问题以及不占用服务器资源
缺点在于JWT是无状态的,一旦签发就管不着了,不能修改有效期、强制过期等,这对于Web论坛这种用户登录认证来说是不合理的,要维护用户状态需要服务端额外的实现
讲一讲点赞
之所以用Redis而不用MySQL的主要原因是:
- 做MySQL数据库查询太慢了,内存操作快得多
- 点赞的数据量和并发可能都会比较大,直达数据库会给数据库带来巨大压力
点赞主要使用的Redis中的HashMap数据结构,key是用户、帖子、评论、回复的ID,其中value值是一个set,因为不能重复点赞同时要做记录
这边使用策略+工厂模式
定时将数据持久化到数据库,当然可能会存在Redis宕机数据丢失的情况,不过点赞对数据要求不高,丢掉一点也没问题
考虑过高并发场景下的点赞吗?
- 用户点赞\取消点赞方法中,Redis事务没有保证
- 该应用只适用于单机环境,分布式环境下存在并发问题,分布式锁待完成
- 高并发下对set的操作可能会有很高的时间复杂度,可以利用Kafka消息队列
讲一讲Redis的持久化
讲一讲热帖排行
排行榜使用Reids做的,会对一个帖子的点赞数、阅读数、评论数、发布时长、是否加精等参数进行综合地算出一个分值(取对数)
帖子会有一个初始分,什么时候会触发计算和更新呢?
接收到请求的时候,会向以帖子ID为key的zset中插入操作记录,然后定时重新计算帖子的权值,并将它刷新到搜索引擎中
Ques:为什么要用Redis,用别的数据库、用MySQL不行吗?
讲一讲网站数据统计
网站数据统计访客数和日活跃用户数
访客数通过对IP排重,用到了Redis的HyperLogLog数据结构,性能好,存储空间小
Ques:讲一讲HyperLogLog,为什么要用它?
因为对于排重统计而言,无论是set还是bitmap,当数据量非常庞大时,他们所占用的内存空间也会膨胀到无法接受的地步,原本内存相对于磁盘就更加捉襟见肘
同时,这类场景对数据要求很低,它只需要一个去重的统计结果,而不需要能够说把数据重新拿出来,或者对数据做搜索之类的需求
这便是【基数统计】的应用场景
HyperLogLog几乎是专门为这一场景而生的,1即便是集合中数据量巨大,它占用的内存也非常少,2它所需的内存总是固定的,最多12KB,不会因数据量而膨胀
活跃用户数则是通过对登录用户ID进行排重统计,数据结构用的是Bitmap
Ques:讲一讲BitMap,为什么这两个统计要用不同的数据结构?
Redis缓存与数据库数据一致性的问题
双写一致性
先更新数据库,再淘汰ache
无论是同步/异步更新缓存,都不会导致数据的最终不一致,在更新数据库期间,cache中的旧数据会被读取,可能会有一段时间的数据不一致,但读的效率很好
为什么用ElasticSearch?用别的数据库行不行?为什么ElasticSearch做搜索快?
Tips:这边可以把面试官往MySQL索引上面引
在MySQL中,对主键建立聚集索引,底层使用B+树,然后通过目录页找到数据页,最后找到数据
查询非主键字段,可以建立非聚簇索引,有索引覆盖等技术解决优化回表等问题,速度其实也还可以
但是,对于全文检索比如LIKE %张三
这样是不走索引的模糊查询,就会触发全表扫描,全表扫描是非常慢的,需要顺序遍历匹配所有记录,尤其是在数据量庞大的情况下甚至难以接受
这个例子的话,
%
放前面会导致索引失效
而且匹配到的结果往往不能让人满意
而elasticSearch快的关键在于倒排索引
ES 可以说是对 Lucene 的一个封装,里面关于倒排索引的实现就是通过 lucene 这个 jar 包提供的 API 实现的
将分词后得到的trem建立倒排索引
倒排索引是一种用于快速全文搜索的结构,由文章中所有不重复单词的列表构成
对于其中每个词,有一个包含它的文档列表
通常情况下并不是严格要求的一模一样的存在
当然这样建立的倒排索引必然是非常大的,因为trem肯定不会少,于是,就有一个term dictionary用来快速定位,他对trem排序后采用二分查找来找到指定的trem
但即便如此,对于磁盘IO到内存来说,term dictionary还是太大了,于是又有了trem index,他是一颗前缀字典树(tire 树)
再加上一些压缩技术,使得内存缓存整个term index变成可能
为什么要用缓存,为什么要用Caffine做二级缓存?
提升响应速度,减小系统压力与性能消耗
主要是CPU运算和磁盘、网络IO交互
相对于分布式缓存中间件Redis,Caffine Cache是本地缓存,特点是
- 高性能
- 基于LRU算法实现,支持多种缓存过期策略
手撕:那你写一下LRU
Caffine做应用内的一级缓存,Redis做二级缓存
之所以要建二级缓存的原因,主要有两点
- 尽管相对于数据库的磁盘读取,Redis的内存读取已经很快了,但是本地缓存可以做到更快,更好的访问性能
这个思路也类似于CPU中的L1、L2、L3多级缓存
MyBatis中的多级缓存
ARP协议中的缓存表
- 如果是远程Redis,那么带来的速度提升会更大,减少了网络IO
- 提高系统容错性和可用性,避免缓存击穿等问题,两级缓存都挂了可能新小
策略是:
- 对于变更频率较高的数据,采用集中式缓存
- 极少变更的数据、或是短期内对一致性要求不高的数据,采用本地缓存
- 对于需要分布式共享的数据,如:用户凭证,不适合存在本地Coffine缓存
你怎么考虑二级缓存和数据库之间的一致性问题?
三种,
- 旁路型,业务自行负责与缓存和数据库之间的交互
但是就可能出现数据一致性,以及缓存击穿、穿透和雪崩的问题
八股文:那你说说什么是缓存击穿、缓存穿透和缓存雪崩,如何解决?
- 穿透型
就是我们常见的先找缓存,缓存未命中再找数据库,然后更新缓存的情况
这里考虑双写一致性的话又要分四种不同的情况考虑
八股文:那你展开说说
- 异步型
也是这边项目中使用的类型,策略是所有请求涉及的数据实时读写都是基于缓存进行的
此外,用一个独立线程单独实现一个数据持久化操作,将变更数据写入数据库中
数据库在这里只相当于一个备份,而不参与系统业务的运行了
八股文:那你讲讲Redis的数据持久化
讲一讲项目里用到的Kafka
项目中使用Kafka实现异步的站内通知,包括用户间私信和全站通知
为什么要用Kafka?
异步、解耦、削峰
它和RabbitMQ一类的消息队列有什么区别,选择用它
- 适用于对可靠性要求较高的场景
会有什么问题吗?
因为完全依托于缓存层,而缓存层是运行于内存上的,所以如果发生部分缓存更新完还没来得及持久化,突然缓存服务宕机,就可能丢失这一部分数据
直达数据库后,Redis和本地缓存的更新都是加锁的
会有什么问题吗?
分布式环境下,一级缓存可能出现缓存漂移的问题,即:不同节点的一级缓存数据不一致
这种情况下,如果去掉本地,只采用Redis集中式缓存的话不会有这个问题,但是又会有网络IO的消耗问题
为什么要用Redis?
为了优化对帖子的访问
具体是什么?为什么能优化帖子的访问?把什么对象放到了Redis里?
帖子是怎么访问的?在前端页面点击一个链接,被Tomcat接收并由DispachterServlet处理,去找到相应的Controller接口接收请求并处理后,返回一个ModelAndView对象,最后由模板引擎将ModelAndView渲染成页面
那么模板引擎给短链接加头加尾凑成一个完成的链接是在哪里发生的?ModelAndView是返回给谁?Servlet还是Tomcat,模板引擎又是在哪个时机渲染的?
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/16828084.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步