【Redis】基础3:一些应用场景

文章目录

  • [1. session管理](#1. session管理)
    • [1.1 手机号登录流程](#1.1 手机号登录流程)
    • [1.2 session的数据结构设计](#1.2 session的数据结构设计)
      • [1.2.1 一些概念](#1.2.1 一些概念)
      • [1.2.2 session数据结构例子](#1.2.2 session数据结构例子)
    • [1.3 引入redis来实现共享session](#1.3 引入redis来实现共享session)
  • [2. 限时抢购代金券](#2. 限时抢购代金券)
    • [2.1 业务流程](#2.1 业务流程)
    • [2.2 代金券表设计](#2.2 代金券表设计)
    • [2.3 高并发场景面临的问题](#2.3 高并发场景面临的问题)
      • [2.3.1 问题](#2.3.1 问题)
      • [2.3.2 工具](#2.3.2 工具)
      • [2.3.3 解决方案](#2.3.3 解决方案)

1. session管理

1.1 手机号登录流程

  • 发送短信验证码流程:输入手机号 --> 验证手机号合法(否则回到"输入手机号") --> 生成验证码 --> 保存验证码到session --> 发送验证码短信。

  • 验证码登录流程:输入手机号、验证码 --> 校验验证码(session中的有没有用户提交的验证码) --> 校验通过,以手机号找用户 --> 用户存在,下一步;用户不存在,则创建用户,再下一步 --> 保存用户信息到session。

  • 登录检查流程:请求携带cookie ,从cookie中拿session id --> 根据session id拿session对象,判断用户是否在session中(用户登录过则在seesion中有记录) --> 用户不存在终止请求响应,或者重定向到登录页;用户存在,继续响应,注意要缓存用户信息,方便后续使用。

如果采用单体服务-单线程-多协程的方式来处理请求,那么session是线程的数据,协程共享它。如果考虑负载均衡而使用多个server实例,那么session要在这些服务实例之间共享,此时只能使用redis(在内存,kv,server实例之间共享)。即session是多个server实例之间共享的状态。

1.2 session的数据结构设计

1.2.1 一些概念

什么是web应用的状态:客户端与服务器在多次交互过程中产生的上下文信息,例如用户登录凭证、购物车内容、操作历史等。

为什么需要状态:判断请求之间的关联性。如判断两次请求是否来自同一个用户,判断两次请求是否来自同一客户端。

session的作用:HTTP是无状态协议,因此需要使用session(服务端维护)跟踪用户状态,常见的状态化机制还有Cookie(服务端分发,客户端携带),Token(服务端分发,客户端携带)。

1.2.2 session数据结构例子

python 复制代码
session_obj1 = {
    'user_id': 'abc',
    'phone': '13112341234',
    'expire_time': 1745738823
}
session_obj2 = {
    'user_id': 'ABC',
    'phone': '13112341234',
    'expire_time': 1745738823
}
session = {
    '001': session_obj1,
    '002': session_obj2
}

1.3 引入redis来实现共享session

redis中保存两类数据:每个手机号的申请的验证码;登录成功的用户信息

1.3.1 流程

发送验证码短信的流程

输入手机号 --> 验证手机号合法(否则回到"输入手机号") --> 生成验证码 --> 保存验证码到redis,注意加过期时间 ( eg, key=phone:13212341234, val=31245 ) --> 发送验证码短信。

验证码登录流程

输入手机号、验证码 --> 校验验证码(redis中,verify_code = GET phone:13212341234, if verify_code == in_verify_code) --> 校验通过,以手机号找用户 --> 用户存在,下一步;用户不存在,则创建用户,再下一步 --> 保存用户信息到redis( 方式一:用户信息序列化为string形式保存,方式二:直接使用hash,key的格式:token:uuid )。

登录检查流程

请求携带cookie ,从cookie中拿token --> 根据token从redis拿用户信息 --> 拿到用户信息,继续响应,注意要缓存用户信息,方便后续使用同时刷新token过期时间,保证只要用户有请求,登录状态就一直保持;没拿到用户信息,终止请求响应,或者重定向到登录页。

1.3.2 要考虑的问题

问题:如果用户登录后,相当长的一段时间访问那些不需要登录认证的页面,则token一直不会被刷新而自动掉线,这是不合理的。

解决:所有路径都执行刷新token的动作(根据请求cookie中的token访问redis,获取用户信息,用线程变量缓存用户信息,刷新token过期时间),在需要登录认证的路径做额外的登录状态检查工作(检查缓存中是否有用户信息,如果没有则终止继续响应或者重定向到登录页;如果有则继续响应)。

2. 限时抢购代金券

2.1 业务流程

基本流程:查询代金券券(by id) --> 检查时效 --> 检查库存 --> 扣减库存 --> 创建代金券订单并返回订单id

一人只能购买一个单限制下的流程:查询代金券券(by id) --> 检查时效,在时效内继续 --> 检查库存,库存充足继续 --> 根据用户id和代金券di检查代金券订单,订单不存在继续 --> 扣减库存 --> 创建代金券订单并返回订单id

2.2 代金券表设计

对象:普通代金券,限时抢购代金券,代金券订单

表设计:

voucher(voucher_id, shop_id, title, sub_title, rules, pay_value, actual_value, type, status, create_time, update_time)

time_lmt_voucher(voucher_id, stock, start_time, end_time, create_time, update_time)

voucher_order(id, user_id, voucher_id, pay_type, status, pay_time, use_time, refund_time, create_time, update_time)

说明:其中,voucher和time_lmt_voucher是一对一关系,time_lmt_voucher是voucher的扩展。

2.3 高并发场景面临的问题

2.3.1 问题

  1. 超卖(库存为负数):扣减库存逻包含两个操作:读库存并判断库存是否充足,假设初始情况下库存为1(记为op1);更新库存为0(记为op2)。线程1执行op1后线程2也执行op1,然后线程1执行op2,库存为0,线程2再执行op2,库存为-1。
  2. 一人一单限制失效:业务逻辑包含两个操作:根据用户id和代金券id查询代金券订单是否存在,假设初始情况下用户没有代金券订单(记为op1);创建新订单(记为op2)。线程1执行op1后,线程2也执行op1,然后线程1执行op2,创建一个订单,线程2再执行op2,又创建了一个订单。
  3. 使用数据库的自增id作为订单id存在风险(如根据订单id差值推测出订单量等),且订单数量可能受限。

2.3.2 工具

乐观锁:线程不安全不一定发生,不加锁,只有在更新数据时才检查数据是否被已经被修改。使用版本号控制,先访问数据得到版本好,更新时比较版本号,版本号一致则更新数据同时更新版本号,版本号不一致则拒绝更新。

悲观锁:线程不安全一定发生,在访问数据前加锁。

2.3.3 解决方案

  1. 超卖(库存为负数):使用CAS(Compare And Set)原则,限制库存更新操作条件,用op1查询的库存结果来限制op2的更新操作,set time_lmt_voucher into stock=stock-1 where stock=1;
  2. 一人一单限制失效:使用互斥锁构建临界区,把op1和op2放进去。单体服务用进程锁,线程锁,协程锁。分布式服务使用分布式锁。
  3. 使用redis做一个全局id生成器(唯一性,高可用,高性能,递增,安全),id(64bits): 时间戳(32bist) + 序列号(32bits)。
相关推荐
FAQEW14 分钟前
Redis的简单介绍
数据库·redis·缓存
十夫长15 分钟前
Redis Info 性能指标描述
数据库·redis·缓存
枫叶20001 小时前
OceanBase数据库-学习笔记4-租户
数据库·笔记·学习·oceanbase
辰哥单片机设计3 小时前
LCD1602液晶显示屏详解(STM32)
数据库·mongodb
夜光小兔纸3 小时前
SQL Server 数据库重命名
运维·数据库·sql server
多多*4 小时前
SQL语句练习 自学SQL网 多表查询
数据库·数据仓库·hive·hadoop·sql·mysql·mybatis
maomi_95264 小时前
Mysql之数据库基础
数据库·mysql
XY.散人4 小时前
初识Redis · 分布式锁
数据库·redis·分布式
Elastic 中国社区官方博客5 小时前
Elasticsearch:没有 “AG” 的 RAG?
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索