当前位置: 首页 > news >正文

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

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存在并被成功删除说明是第一次请求则继续处理业务生成订单;如果不存在说明是重复请求,则返回错误提示。

相关文章:

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

1.使用工厂模式和策略模式实现布隆过滤器解决缓存穿透问题 Bitmap Bitmap是一种数据结构,它使用位图来表示数据。在处理大量数据时,Bitmap可以通过将每个数据元素映射到一个位,然后使用位运算来对数据进行操作。 通过使用Bitmap&#xff0c…...

Python酷库之旅-第三方库Pandas(005)

目录 一、用法精讲 7、pandas.read_clipboard函数 7-1、语法 7-2、参数 7-3、功能 7-4、返回值 7-5、说明 7-6、用法 7-6-1、代码示例 7-6-2、结果输出 8、pandas.DataFrame.to_clipboard函数 8-1、语法 8-2、参数 8-3、功能 8-4、返回值 8-5、说明 8-6、用法…...

javascripr如何设计弹出输入框并在网页内输出输入内容

javascript如何设计弹出输入对话框 这里就需要用到prompt语言 它的语法格式是 prompt(对话框内容) 如何把在对话框里输入内容输出到网页里,需要先定义一个变量,用var或let都可以。 假定变量名为a,代码是 let aprompt(请输入…...

gitee代码初次上传步骤

ps. 前提是已经下载安装gitee 一、在本地项目目录下空白处右击,选择“Git Bash Here” 二、初始化 git init 三、添加、提交代码(注意add与点之间的空格) git add . git commit -m 添加注释 四、连接、推送到gitee仓库 git remote add …...

android调用openssl库

android 调用openssl库 一、openssl安装编译 下载openssl-1.1.1w.tar.gz和android-ndk-r21e-linux-x86_64.zip解压android-ndk-r21e-linux-x86_64.zip到/opt/pj_ssl目录下,然后配置环境 vim ~/.bashrc增加如下内容 export NDK_HOME/opt/pj_ssl/android-ndk-r21e…...

Hugging face Transformers(3)—— Tokenizer

Hugging Face 是一家在 NLP 和 AI 领域具有重要影响力的科技公司,他们的开源工具和社区建设为NLP研究和开发提供了强大的支持。它们拥有当前最活跃、最受关注、影响力最大的 NLP 社区,最新最强的 NLP 模型大多在这里发布和开源。该社区也提供了丰富的教程…...

kubernetes集群部署:环境准备及master节点部署(二)

主机名IPv4地址IPv6地址角色安装组件操作系统k8s130-node190192.168.XX.190240a:XX::190masterkubeadm、kubelet、containerdAnolis OS 8.94.19.91-28.1.an8.x86_64k8s130-node191192.168.XX.191240a:XX::191nodekubeadm、kubelet、cri-oAnolis OS 8.94.19.91-28.1.an8.x86_64k…...

第8篇 智能合约的商业应用场景解析

一、引言 在区块链技术的众多应用中,智能合约无疑是其中的一颗璀璨明珠。它通过自动化、去中心化和不可篡改的特性,为商业世界带来了革命性的变革。今天,我们将一同探索智能合约在十个不同行业中的实际应用,感受其独特的魅力。 二、智能合约的商业应用案例 供应链管理:…...

Zabbix 配置grafana对接

zabbix对接grafana简介 Zabbix与Grafana对接可以实现更加丰富和美观的数据可视化,可以利用Grafana强大的可视化功能来展示Zabbix收集的数据。 Grafana 本身是提供了Zabbix的对接插件,开箱即用,安装好了之后点击 enable 一下就能启用。然后就…...

三相感应电机的建模仿真(2)基于ABC相坐标系S-Fun的仿真模型

1. 概述 2. 三相感应电动机状态方程式 3. 基于S-Function的仿真模型建立 4. 瞬态分析实例 5. 总结 6. 参考文献 1. 概述 前面建立的三相感应电机在ABC相坐标系下的数学模型是一组周期性变系数微分方程(其电感矩阵是转子位置角的函数,转子位置角随时…...

开源全新H5充值系统源码/自定义首页+充值页面/灵活对接上游渠道接口

开源全新H5充值系统源码,系统基于thinkphp框架开发,功能已全完善,可灵活对接其他上游渠道接口,默认对接了大猿人接口,另外可无限制自定义创建充值页面,首页支持后台自定义修改,支持三级分销&…...

Linux查看文件的行数,字数,字节数

介绍 在Linux系统中这统计非常方便,只需要简单的几个命令就可以搞定,这个命令就是 wc。 wc --help 用法:wc [选项]... [文件]...或:wc [选项]... --files0-fromF 输出每个指定文件的行数、单词计数和字节数,如果指定…...

【IO】文件操作

🥰🥰🥰来都来了,不妨点个关注叭! 👉博客主页:欢迎各位大佬!👈 文章目录 1. 文件1.1 认识文件1.2 分清操作的是内存还是硬盘1.3 路径1.3.1 目录结构1.3.2 相对和绝对路径 1.4 文本文件…...

代码随想录算法训练营第74天:路径总结[1]

代码随想录算法训练营第74天:路径总结 ‍ A * 算法精讲 (A star算法) 卡码网:126. 骑士的攻击(opens new window) 题目描述 在象棋中,马和象的移动规则分别是“马走日”和“象走田”。现给定骑士的起始坐标和目标…...

用 Emacs 写代码有哪些值得推荐的插件

以下是一些用于 Emacs 写代码的值得推荐的插件: Ido-mode:交互式操作模式,它用列出当前目录所有文件的列表来取代常规的打开文件提示符,能让操作更可视化,快速遍历文件。Smex:可替代普通的 M-x 提示符&…...

自定义注解-手机号验证注解

注解 package com.XX.assess.annotation;import com.XX.assess.util.MobileValidator;import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*;/*** 手机号校验注解* author super*/ Retention(RetentionPolicy.RUNTIME) Targe…...

华为od-C卷200分题目5 -项目排期

华为od-C卷200分题目5 -项目排期 题目描述 项目组共有N个开发人员,项目经理接到了M个独立的需求,每个需求的工作量不同,且每个需求只能由一个开发人员独立完成,不能多人合作。 假定各个需求之间无任何先后依赖关系,请…...

如何使用Pip从Git仓库安装Python包:深入探索远程依赖管理

如何使用Pip从Git仓库安装Python包:深入探索远程依赖管理 Python的包管理工具Pip使得安装和管理Python库变得非常简单。有时,我们需要安装那些尚未发布到PyPI的包,或者想要尝试最新的开发版本。这时,可以直接从Git仓库安装包。本…...

计算机专业怎么选择电脑

现在高考录取结果基本已经全部出来了,很多同学都如愿以偿的进入到了计算机类专业,现在大部分同学都在为自己的大学生活做准备了,其中第一件事就是买电脑,那计算机类专业该怎么选择电脑呢? 计算机专业是个一类学科&…...

当前国内可用的docker加速器搜集 —— 筑梦之路

可用镜像加速器 以下地址搜集自网络,仅供参考,请自行验证。 1、https://docker.m.daocloud.io2、https://dockerpull.com3、https://atomhub.openatom.cn4、https://docker.1panel.live5、https://dockerhub.jobcher.com6、https://hub.rat.dev7、http…...

【腾讯内推】腾讯2025校招/青云计划/社招——长期有效

及时跟进进度,保证不让简历石沉大海! 涵盖NLP/CV/CG/ML/多模态/数据科学/多媒体等各方向! 定向匹配优质团队/竞争力薪酬/覆盖全球工作地点! 招聘对象: 本硕博:2024年1月-2025年12月毕业的同学 目前最热岗位: 技术研究-自然语言处理 技术研究-计算机视觉 …...

集群限流sentinel实践

参考: 集群模式 实践 集群流控规则 其中 用一个专门的 ClusterFlowConfig 代表集群限流相关配置项,以与现有规则配置项分开: // 全局唯一的规则 ID,由集群限流管控端分配. private Long flowId;// 阈值模式,默认&…...

Flutter-实现双向PK进度条

如何实现一个双向PK进度条 在Flutter应用中,进度条是一个非常常见的组件。而双向PK进度条则能够展示两个对立的数值,如对战中的双方得分对比等。本文将介绍如何实现一个具有双向PK效果的进度条,并支持竖直和斜角两种过渡效果。 1. 需求 我…...

unix高级编程系列之文件I/O

背景 作为linux 开发者,我们不可避免会接触到文件编程。比如通过文件记录程序配置参数,通过字符设备与外设进行通信。因此作为合格的linux开发者,一定要熟练掌握文件编程。在文件编程中,我们一般会有两类接口函数:标准…...

PySide(PyQt),记录最后一次访问文件的路径

1、在同目录下用文本编辑器创建JSON文件,命名为setting.json,并输入以下内容后保存: { "setting": { "last_file": [ "" ] } } 2、应用脚本: import json …...

wordpress企业网站模板免费下载

大气上档次的wordpress企业模板,可以直接免费下载,连注册都不需要,网盘就可以直接下载,是不是嘎嘎给力呢 演示 https://www.jianzhanpress.com/?p5857 下载 链接: https://pan.baidu.com/s/1et7uMYd6--NJEWx-srMG1Q 提取码:…...

[leetcode hot 150]第一百一十七题,填充每个节点的下一个右侧节点

题目: 给定一个二叉树: struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL 。 初始状态下&#x…...

Docker 入门篇(十 一)-- 网络配置总结

Docker 容器技术的核心优势之一是其轻量级的虚拟化和隔离性,而 Docker 网络则是实现容器间以及容器与外界通信的关键。以下是对 Docker 网络的关键知识点的总结。 一、 Docker 网络概述 Docker 网络允许容器进行相互通信以及与外部网络的连接。Docker 提供了多种网…...

【Android面试八股文】Android 有哪些存储数据的方式?

在Android平台上,有多种方式可以存储数据,每种方式都适合不同类型的数据和使用场景。以下是主要的存储数据方式: SharedPreferences(轻量级数据存储): SharedPreferences是用于存储简单键值对数据的最简单方法,适合存储用户偏好设置、配置信息等。数据以XML文件形式存储…...

3. train_encoder_decoder.py

train_encoder_decoder.py #__future__ 模块提供了一种方式,允许开发者在当前版本的 Python 中使用即将在将来版本中成为标准的功能和语法特性。此处为了确保代码同时兼容Python 2和Python 3版本中的print函数 from __future__ import print_function # 导入标准库…...