黑马苍穹外卖技术亮点 详情

1.使用工厂模式和策略模式实现布隆过滤器解决缓存穿透问题

Bitmap

Bitmap是一种数据结构,它使用位图来表示数据。在处理大量数据时,Bitmap可以通过将每个数据元素映射到一个位,然后使用位运算来对数据进行操作。
通过使用Bitmap,我们可以快速地完成排序、查找和去重等操作。优点极大的节省储存空间。但是,Bitmap也存在一些局限性,例如它只能表示有限的数值类型,并且对于数据稀疏的情况可能不太适用。

布隆过滤器

布隆过滤器是一种用于快速检索一个元素是否可能存在于一个集合中的数据结构
它的基本原理是利用多个哈希函数,将一个元素映射成多个位,然后将这些位设置为1。当查询一个元素时,如果这些位都被设置为1,则认为元素可能存在于集合中。布隆过滤器的优点在于它的内存占用极少,并且不局限于数值类型。但是,由于哈希冲突的存在,布隆过滤器也存在误判的可能。

缓存穿透

访问的资源不存在,而导致这个不存在的数据每次请求都要到数据库中去查询,导致数据库挂掉

用布隆过滤器解决缓存穿透问题

不直接访问数据库,而是先通过布隆过滤器判断访问的资源是否存在,存在则放行,不存在则拦截。
使用BitMap作为布隆过滤器,通过多个哈希函数来将被访问的元素映射到位数组中的多个位置上,将对应的位置设置为1。
当需要判断一个元素是否在布隆过滤器中时:只需将该元素进行多次哈希,并检查对应的位数组位置是否都为1,如果其中有任意一位为0,则说明该元素不在集合中;如果所有位都为1,则说明该元素可能在集合中(因为有可能存在哈希冲突),需要进一步检查。

使用工厂模式和策略模式解决缓存穿透问题

  1. 定义布隆过滤器接口:首先定义一个布隆过滤器接口,包括添加元素和判断元素是否存在两个基本操作。
  2. 实现具体的布隆过滤器类:创建类,实现布隆过滤器接口中的方法。在这个类中,需要定义布隆过滗器的数据结构(比如位数组)、大小等属性。
  3. 定义哈希策略接口:定义一个哈希策略接口,包含计算哈希值的方法。
  4. 实现具体的哈希策略类创建多个具体的哈希策略类,每个类对应一种哈希函数的计算方法
  5. 创建布隆过滤器工厂类:定义一个布隆过滤器工厂类,其中包含一个用于创建布隆过滤器对象的工厂方法。工厂方法接受布隆过滤器的大小和哈希策略对象作为参数,并返回一个具体的布隆过滤器对象。
  6. 使用布隆过滤器工厂:在需要创建布隆过滤器对象的地方,调用布隆过滤器工厂的工厂方法来创建布隆过滤器对象,并传入相应的哈希策略对象。
    总结:使用策略模式是创建多个具体的哈希策略类,每个类对应一种哈希函数。并且创建布隆过滤器的工厂类。
    当需要创建布隆过滤器对象时,直接调用工厂类并传入相应的哈希策略对象。
    这样可以将对象的创建和哈希函数的选择解耦,更灵活的创建对象和选择哈希函数。

好处

使用工厂模式和策略模式来实现布隆过滤器带来以下好处:

(1)解耦性:工厂模式和策略模式的结合可以将对象的创建和哈希函数的选择分离,使得各部分之间的耦合度降低。这样在需要修改布隆过滤器的具体实现或者切换哈希函数时,只需要修改相应的工厂类或策略类,而不影响其他部分。
(2)可扩展性:通过工厂模式和策略模式,我们可以方便地添加新的布隆过滤器实现类和哈希函数策略类,而不需要修改现有代码。这样在需要增加新的布隆过滤器类型或者新的哈希函数时,只需添加相应的类即可。

2.使用Redis采用一主两从+哨兵的集群方案

使用Redis

当用户数量较多时,用户频繁的访问数据库,数据库压力增大,系统的性能下降。因此使用Redis对数据进行缓存,减小数据库的压力,提高系统的性能和访问速度。

为什么采用一主两从+哨兵的集群方案(解决高并发高可用问题)

进一步提高Redis的并发能力,可以搭建主从集群,实现读写分离
我们项目的redis采用一主二从的集群方案,主节点负责写数据,从节点负责读数据,主节点写入数据之后,需要把数据同步到从节点中,实现了读写分离,解决了高并发问题
哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送ping命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
哨兵可以实现自动故障修复:哨兵可以监测到主节点宕机,自动将从节点切换为主节点并发布通知其他从服务器修改配置文件,当旧主服务器恢复后会成为一个新的从节点。

怎样解决高并发高可用问题

主从集群保证高并发,哨兵保证高可用。

怎样解决数据一致性问题

数据一致性:当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致。
​使用旁路缓存模式在缓存与数据库双写时保持一致性。
先更新数据库,后删除缓存。理论上会出现不一致的情况,但概率较小因为缓存的写入速度是比数据库的写入速度快很多。

**更新缓存替换为删除缓存**,那么**下一次执行的查询操作都会从数据库中加载数据**,此时数据一致性就有了保证。
比较方法时注意:缓存被清空后,线程只能到数据库中查询,在数据库中查完就会直接更新缓存。
先查缓存,再查数据库。
**重点在与看结束后数据库与缓存是否一致,用多久一致的。**
1)先删缓存,再更新数据库:
(多线程调度不确定)可能会导致A删缓存,B去查缓存“空”-->然后去查数据库-->拿着数据库中数据更新缓存-->A更新数据库
结束后:数据库中是A更新后的信息,缓存中是原始信息。(2)先更数据库,再删缓存:
A更数据库,B查缓存-->B拿到原始数据-->A删除缓存
结束后:数据库中新数据,缓存被删即还会获得新数据。【从B在数据库拿到原始数据到写到缓存中,但持续时间相比其他方法短】(3)延迟双删:
A删缓存,B去查缓存“空”-->然后去查数据库-->拿着数据库中数据更新缓存-->A更新数据库-->延迟删除缓存
结束后:相比1最后缓存与数据库时一致的,但性能上不如2

总结:采取旁路缓存使缓存和数据库保持数据的一致性,
读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。
更新的时候,先更新数据库,再删除缓存中对应着数据库更新的数据。

3.使用Spring Task实现订单超时取消,使用WebSocket实现用户催单。

WebSocket

基于TCP的一种新的网络协议。实现了浏览器与服务器全双工通信——浏览器和服务器只需完成一次握手,两者就可以建立连接,双向数据传输。
WebSocket:两边都可以主动通信。
应用场景:网页聊天、视频弹幕,股票信息实时更新(服务器主动推送到网页上的)

订单超时取消流程

客户下单后未支付,订单一直处于“待支付”状态。
使用Spring Task工具的cron表达式设置定时任务触发时间,每分钟检查一次是否存在支付超时的订单,如果存在超时则将订单状态修改为“已取消”。

用户催单流程

用户在小程序中点击催单按钮后,根据用户id查询是否有支付成功的订单,有则调用WebSocke实现服务端向客户端推送消息,展示用户订单和支付成功信息。

4.使用自定义拦截器和JWT令牌实现用户登录认证,用ThreadLocal存储用户ID

用户登录认证流程

(1)用户登录时,发送用户名和密码给服务器,服务器验证通过则生成一个包含用户信息的JWT令牌,并将其发送给客户端。
(2)客户端受到JWT令牌后,保存在本地中,
(3)每当用户发起请求时,将JWT令牌添加到请求头中
(4)服务器端的自定义拦截器会拦截所有请求,从请求头中提取JWT令牌。
(5)拦截器解析JWT令牌,获取用户信息,并将其存储在ThreadLocal中,以避免在每次请求时都去解析JWT令牌。
(6)拦截器可以检查用户是否已经通过认证,通过则处理请求,未通过则返回错误信息。
(7)请求完成后,拦截器remove清楚ThreadLocal里的用户信息

为什么用JWT不用Session

传统的Session用户认证方案:

(1)用户向服务器发送用户名和密码。
(2)服务器验证通过后,在当前**对话(session)**里面保存相关数据,比如用户角色、登录时间等等。
(3)服务器向用户返回一个 session_id,写入用户的 Cookie。
(4)用户随后的每一次请求,都会通过 Cookie将 session_id 传回服务器。
(5)服务器收到 session_id,找到对应的session并获取前期保存的数据,由此得知用户的身份。

这种传统的通过session的方式适用于前后端不分离的情况,因为session是保存在服务器端,因此对于跨域或服务器集群的情况很不友好。
而JWT解决了跨域问题,而且(1)jwt基于json,数据处理方便。(2)使用非对称加密和签名技术,安全性高。(3)资源服务使用JWT,可不依赖认证服务即可完成授权。

为什么用ThreadLocal

ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
这样可以保证线程之间的数据隔离,避免了线程安全问题。

ThreadLocal使用流程

每次执行请求时拦截器将用户信息用set保存在ThreadLocal中,ThreadLocal每次调用set时是一个独立的线程,当另一个用户调用ThreadLocal的set时方法 时,就会新建另一个线程,线程之间互不影响,当对应线程在调用get时候,就会请求到set时候的信息。在拦截器执行过后的方法中添加ThreadLocal线程remove()方法,这样每次请求结束后会将ThreadLocal线程中的数据删除,这样可以防止线程过多内存泄露。

为什么用拦截器不用过滤器、切面

粒度更细: 拦截器可以针对特定的控制器或控制器方法进行拦截,实现精确的拦截逻辑
而过滤器是基于URL路径进行拦截,无法做到针对具体的控制器或方法,切面也是基于切点进行拦截,粒度相对较粗。

5.使用AOP统一记录登录者操作日志

使用AOP切片,将登陆者增删改用户信息的操作信息记录到数据库中。

流程

(1)建表日志信息表
(2)自定义注解,在增删改等方法运行时调用切面
(3)定义切面类,操作者记录:先通过当前请求的请求头拿到JWT令牌并解析出操作者的用户ID,然后记录操作命令和操作时间等信息插入到日志信息表中。

6.使用Redis分布式锁实现高并发商品秒杀,解决超卖问题

为什么不用单体锁

单体应用难以满足实际高并发访问需求,会将单体应用部署到多个tomcat实例上,由负载均衡将请求分发到不同实例上。
单体锁(synchronized、ReentrantLock)是JVM层面的锁,只能控制单个实例上的并发访问安全,多实例下依然存在数据一致性问题。

分布式锁

分布式锁指的是,所有服务中的所有线程都去获取同一把锁,但只有一个线程可以成功的获得锁,其他没有获得锁的线程必须全部等待,直到持有锁的线程释放锁。

RedLock解决Redis集群主从不同步数据丢失问题

Redisson使用主从集群模式,主节点挂掉,从节点没有同步到锁的情况:
使用RedLock,针对Redis中所有节点来进行同步,能够保证超过半数的Redis加锁了才算加锁成功,从而保证并发安全。

解决流程

多用户并发操作的情况下,多个用户尝试购买同一件商品,导致商品库存不足或者超卖。
采用Redis提供的Redisson组件实现Redis分布式锁,来控制并发访问
当一个线程去获取锁,锁的VALUE中存入UUID来保证锁和当前线程绑定
当前线程获取锁成功开始处理业务时,内部会有watch dog看门狗,每隔10s看当前线程是否还持有锁,如果持有则给锁延长生存时间。

当Redis集群部署时,为了解决主节点挂掉从节点没有同步到锁的情况,使用RedLock,针对Redis中所有节点来进行同步,能够保证超过半数的Redis加锁了才算加锁成功,从而保证并发安全。

另外:用户限流,防止同一用户多次秒杀

使用布隆过滤器记录用户和商品ID来解决。
当用户参与秒杀时,判断是否ID是否记录存在布隆过滤器中,不存在证明该用户是第一次参与秒杀改商品,放行继续后续业务;
过滤器中存在,则禁止继续秒杀。

7.基于Redis使用防重Token和lua脚本,防止重复提交订单

lua脚本作用

使用lua脚本实现原子性的查询并删除操作。为了确保即使多个请求同时到达,也只有一个请求能够成功删除Token。

流程

用户发起请求时,服务端生成唯一的token作为信息凭证
将Token存入Redis并设定过期时间,防止Redis内存溢出。
在后续请求中要携带这个Token,服务器收到后,在Redis中通过lua脚本进行原子性的查询并删除操作
如果Token存在并被成功删除说明是第一次请求则继续处理业务生成订单;如果不存在说明是重复请求,则返回错误提示。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/41511.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++期末整理

课堂笔记 构造与析构 #include <iosteam> #include <cstring> using namespace std;struct Date {int y, m, d;void setDate(int, int, int);Date(int yy, int mm, int dd) {y yy, m mm, d dd;} };class Student { private:char* name;Date birthday; public:…

视频号矩阵源码:构建短视频生态的基石

在数字化时代&#xff0c;视频内容已成为连接品牌与消费者的重要桥梁。视频号矩阵源码&#xff0c;作为短视频营销自动化的创新引擎&#xff0c;正在帮助内容创作者和营销团队以前所未有的效率和智能&#xff0c;管理和扩展他们的视频内容。本文将深入探讨视频号矩阵源码的核心…

RTL8211FSI PHY电路设计

文章目录 硬件设计引脚功能框图说明PHYADDRPageLED 模式自动协商/速度/全半双工模式Soft Reset上电顺序 原理图设计参考 软件控制&#xff08;FPGA&#xff09;硬件调试 硬件设计 引脚 笔者前代数字采集板采用的 PHY 芯片是博通 Boardcom 的 B50610&#xff0c;其仅支持 0 ∼…

leetcode 152. 乘积最大子数组「贪心」「动态规划」

152. 乘积最大子数组 题目描述&#xff1a; 给你一个整数数组nums&#xff0c;请你找出数组中乘积最大的非空连续子数组&#xff0c;并返回该子数组所对应的乘积 思路1&#xff1a;贪心 由于 n u m s [ i ] nums[i] nums[i]都是整数&#xff0c;所以多乘一些数肯定不会让绝…

Java 方法中循环调用具有事务的方法

在Java中&#xff0c;循环调用一个具有事务的方法时&#xff0c;需要特别注意事务的边界和管理。通常&#xff0c;事务的边界是由框架&#xff08;如Spring&#xff09;来控制的&#xff0c;确保方法执行时数据的完整性和一致性。然而&#xff0c;在循环中调用事务方法时&#…

RAG:本地部署Langchain-Ollma(Windows)

RAG&#xff1a;本地部署Langchain&#x1f99c;&#x1f517;-Ollma&#x1f42b;(Windows) RAG&#xff0c;即“Retrieval Augmented Generation”&#xff08;检索增强生成&#xff09;&#xff0c;是一种结合了检索和生成技术的自然语言处理模型。它主要用于文本生成任务&…

对SRS媒体服务器进行漏洞扫描时,SRS的API模块会出现漏洞,如何修补这些漏洞的简单方法

目录 一、引言 1、srs介绍 2、媒体流介绍 3、应用场景 二、SRS的http_api介绍、及漏洞 1、概述 2、http_api模块的作用 &#xff08;1&#xff09;提供HTTP API服务 &#xff08;2&#xff09;管理和监控SRS服务器 &#xff08;3&#xff09;自定义开发 三、漏洞扫描…

单位立方体各个面上的法向量,向量场以及每个面上的通量

单位立方体各个面上的法向量&#xff0c;向量场 F ( x , y , z ) \mathbf{F} (x, y, z) F(x,y,z) 以及每个面上的通量 flyfish 假设我们有一个单位立方体&#xff0c;向量场 F ( x , y , z ) \mathbf{F} (x, y, z) F(x,y,z) 在该立方体上。 法向量 &#xff1a;单位立方…

情绪识别反馈训练系统

系统应用简介 情绪识别检测训练系统可以通过语音、实时面部表情、静态情绪图片智能检测使用者的情绪&#xff0c;对异常情绪进行预警&#xff0c;以达到及时明晰情绪状态并辅助缓解负性情绪的目的。 应用范围&#xff1a;适用于年满足12周岁及以上人群。 二、系统基本原理 …

前端面试题14(贝塞尔曲线)

贝塞尔曲线在前端开发中经常用于创建平滑的动画路径或绘制复杂的矢量图形。贝塞尔曲线可以是一次、二次或三次的&#xff0c;其中三次贝塞尔曲线是最常见的&#xff0c;因为它提供了足够的灵活性来创建各种形状&#xff0c;同时保持计算上的可行性。 下面我将解释三次贝塞尔曲…

代码随想录算法训练营第五十九天 | 110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长、复习

110.字符串接龙 题目链接&#xff1a;https://kamacoder.com/problempage.php?pid1183 文档讲解&#xff1a;https://programmercarl.com/kamacoder/0110.%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%8E%A5%E9%BE%99.html 思路 本题只需要求出最短路径的长度就可以了&#xff0c;不用找出…

使用 Qt 实现自定义拖动窗口

文章目录 如何在 Qt 中实现无标题栏窗口的拖动准备工作创建自定义窗口类使用 QDialog 实现拖动功能详细解释代码行解释 小结 如何在 Qt 中实现无标题栏窗口的拖动 在许多桌面应用程序中&#xff0c;我们经常需要自定义窗口外观&#xff0c;包括去掉标题栏&#xff0c;使窗口看…

SQL Server端口配置指南:最佳实践与技巧

1. 引言 SQL Server通常使用默认端口1433进行通信。为了提高安全性和性能&#xff0c;正确配置SQL Server的端口非常重要。本指南将帮助您了解如何配置和优化SQL Server的端口设置&#xff0c;以满足不同环境和需求。 2. 端口配置基础 2.1 默认端口 SQL Server的默认端口是…

LabVIEW幅频特性测试系统

使用LabVIEW软件开发的幅频特性测试系统。该系统整合了Agilent 83732B信号源与Agilent 8563EC频谱仪&#xff0c;通过LabVIEW编程实现自动控制和数据处理&#xff0c;提供了成本效益高、操作简便的解决方案&#xff0c;有效替代了昂贵的专用仪器&#xff0c;提高了测试效率和设…

一款EF Core下高性能、轻量级针对分表分库读写分离的解决方案

ShardingCore项目介绍 ShardingCore是一款开源、简单易用、高性能、普适性&#xff0c;针对EF Core生态下的分表分库的扩展解决方案&#xff0c;支持EF Core2的所有版本&#xff0c;支持EF Core2的所有数据库、支持自定义路由、动态路由、高性能分页、读写分离的一款EF Core拓展…

华为云生态和快速入门

华为云生态 新技术催生新物种&#xff0c;新物种推动新生态 数字技术催生各类运营商去重塑并颠覆各行业的商业模式 从业务层面看&#xff0c;企业始终如一的目标是业务增长和持续盈利&#xff0c;围绕这些目标衍生出提质、增效、降本、安全、创新和合规的业务诉求&#xff0c…

本迪戈和阿德莱德银行与MongoDB合作, 利用生成式AI对银行核心技术进行现代化改造

MongoDB公司&#xff08;纳斯达克股票代码&#xff1a;MDB&#xff09;近日宣布与本迪戈和阿德莱德银行 (Bendigo and Adelaide Bank&#xff0c;澳大利亚证券交易所股票代码&#xff1a;BEN&#xff09;建立合作伙伴关系。 本迪戈和阿德莱德银行将使用MongoDB Atlas对其银行核…

【PTGui、Pano2VR6、UE4】VR全景拍摄及漫游交互制作操作实例(更新中)

一、基本思路 首先进行VR全景拍摄&#xff0c;获取高质量的全景图像&#xff1b;然后使用PTGui进行图像拼接&#xff0c;确保图像的连续性与准确性&#xff1b;接着利用Pano2VR6进行VR漫游的制作&#xff0c;添加交互元素与多媒体内容&#xff1b;最后进行作品的调试与优化&am…

条件筛选1-4题(30 天 Pandas 挑战)

条件筛选 1. 相关知识点1.1 query条件或查询1.2 query条件与查询1.3 存在查询及列名修改1.4 条件查询&#xff0c;相等1.5 删除重复值1.6 排序 2. 题目2.1 大的国家2.2 可回收且低脂的产品2.3 从不订购的客户2.4 文章浏览 I 1. 相关知识点 1.1 query条件或查询 # |或 world.q…

三星组件新的HBM开发团队加速HBM研发

为应对人工智能(AI)市场扩张带来的对高性能存储解决方案需求的增长&#xff0c;三星电子在其设备解决方案(DS)部门内部成立了全新的“HBM开发团队”&#xff0c;旨在提升其在高带宽存储器(HBM)领域的竞争力。根据Business Korea的最新报告&#xff0c;该团队将专注于推进HBM3、…