仿12306校招项目业务三(用户注册)

news2025/1/20 13:27:57

用户表结构

原本的表结构如下

由于用户量大,采用分库分表:

分库分表设计

根据系统设计的假设,12306 的注册用户规模约为 10 亿,每年新增用户约 1000 万。在用户数据分库或分表之前,我们需要先考虑拆分成多少个库或表才能达到最优性能。为了进行这样的决策,我们可以预估单个表的最大数据量。根据过去的经验,通常我们会选择 2000 万作为一个经验值。这个数据量既不会过小,同时又能保证增删改查等操作相对流畅。

根据当前用户表的数据量为 10 亿,并且每年新增 1000 万用户,预估未来系统的生命周期较长,数据量大概会达到 30 亿左右。基于这个数据量,我们预估单表的数据量在2000 万左右,因此需要分大约 150 张表来容纳这些数据。

在进行分库分表容量评估时,我们通常会尽可能多地进行评估。这样做的好处是,即使每张表的数据量不多,也能及早发现拆分后是否存在数据问题,以便及时进行调整和优化。此外,需要特别指出的是,我们对表数据量考虑的阈值相对较小,这是因为我们的系统具备良好的可扩展性,可以轻松应对大量的数据增长。因此,基于这种情况的分库分表策略,即使在几百年后,这个分库分表依然能够处理数据,并且不会出现性能问题。这为我们的系统提供了稳定可靠的性能障。

选择分库分表中的分片键(Sharding Key)是一个关键决策,它直接影响了分库分表的性能和可扩展性。以下是一些选择分片键的关键因素:

1. 访问频率:选择分片键应考虑数据的访问频率。将经常访问的数据放在同一个分片上,可以提高查询性能和降低跨分片查询的开销。

2. 数据均匀性:分片键应该保证数据的均匀分布在各个分片上,避免出现热点数据集中在某个分片上的情况。

3. 业务关联性:分片键应该与业务关联紧密,这样可以避免跨分片查询和跨库事务的复杂性。

4. 数据不可变:一旦选择了分片键,它应该是不可变的,不能随着业务的变化而频繁修改。

基于以上考虑,我们选择使用 username 作为分片键。

分库分表实现

使用 ShardingSphere 分库分表操作,可以查看官网进行一些前置条件理解:

数据分片 :: ShardingSphere

1. 引入 ShardingSphere 依赖

<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core</artifactId>
<version>5.3.2</version>
</dependency>

2. 定义分片规则

spring:
  application:
    name: index12306-user${unique-name:}-service
  datasource:
    driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
    url: jdbc:shardingsphere:classpath:shardingsphere-config.yaml

3. 用户分片配置

因为 12306 更多的是向大家演示分库分表,所以分 2 个库以及对应业务 16 张表。

shardingsphere-config.yaml:

dataSources:
  ds_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/12306_user_0?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
    username: root
    password: root

  ds_1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/12306_user_1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
    username: root
    password: root

rules:
  - !SHARDING
    tables:
      t_user:
        actualDataNodes: ds_${0..1}.t_user_${0..31}
        databaseStrategy:
          standard:
            shardingColumn: username
            shardingAlgorithmName: user_database_hash_mod
        tableStrategy:
          standard:
            shardingColumn: username
            shardingAlgorithmName: user_table_hash_mod
      t_passenger:
        actualDataNodes: ds_${0..1}.t_passenger_${0..31}
        databaseStrategy:
          standard:
            shardingColumn: username
            shardingAlgorithmName: passenger_database_hash_mod
        tableStrategy:
          standard:
            shardingColumn: username
            shardingAlgorithmName: passenger_table_hash_mod
      t_user_mail:
        actualDataNodes: ds_${0..1}.t_user_mail_${0..31}
        databaseStrategy:
          standard:
            shardingColumn: mail
            shardingAlgorithmName: t_user_mail_database_hash_mod
        tableStrategy:
          standard:
            shardingColumn: mail
            shardingAlgorithmName: t_user_mail_table_hash_mod
      t_user_phone:
        actualDataNodes: ds_${0..1}.t_user_phone_${0..31}
        databaseStrategy:
          standard:
            shardingColumn: phone
            shardingAlgorithmName: t_user_phone_database_hash_mod
        tableStrategy:
          standard:
            shardingColumn: phone
            shardingAlgorithmName: t_user_phone_table_hash_mod
    shardingAlgorithms:
      user_database_hash_mod:
        type: CLASS_BASED
        props:
          sharding-count: 32
          table-sharding-count: 16
          strategy: standard
          algorithmClassName: org.opengoofy.index12306.framework.starter.database.algorithm.sharding.CustomDbHashModShardingAlgorithm
      passenger_database_hash_mod:
        type: CLASS_BASED
        props:
          sharding-count: 32
          table-sharding-count: 16
          strategy: standard
          algorithmClassName: org.opengoofy.index12306.framework.starter.database.algorithm.sharding.CustomDbHashModShardingAlgorithm
      t_user_mail_database_hash_mod:
        type: CLASS_BASED
        props:
          sharding-count: 32
          table-sharding-count: 16
          strategy: standard
          algorithmClassName: org.opengoofy.index12306.framework.starter.database.algorithm.sharding.CustomDbHashModShardingAlgorithm
      t_user_phone_database_hash_mod:
        type: CLASS_BASED
        props:
          sharding-count: 32
          table-sharding-count: 16
          strategy: standard
          algorithmClassName: org.opengoofy.index12306.framework.starter.database.algorithm.sharding.CustomDbHashModShardingAlgorithm
      passenger_table_hash_mod:
        type: HASH_MOD
        props:
          sharding-count: 32
      t_user_mail_table_hash_mod:
        type: HASH_MOD
        props:
          sharding-count: 32
      t_user_phone_table_hash_mod:
        type: HASH_MOD
        props:
          sharding-count: 32
      user_table_hash_mod:
        type: HASH_MOD
        props:
          sharding-count: 32
  - !ENCRYPT
    tables:
      t_user:
        columns:
          id_card:
            cipherColumn: id_card
            encryptorName: common_encryptor
          phone:
            cipherColumn: phone
            encryptorName: common_encryptor
          mail:
            cipherColumn: mail
            encryptorName: common_encryptor
          address:
            cipherColumn: address
            encryptorName: common_encryptor
      t_passenger:
        columns:
          id_card:
            cipherColumn: id_card
            encryptorName: common_encryptor
          phone:
            cipherColumn: phone
            encryptorName: common_encryptor
        queryWithCipherColumn: true
    encryptors:
      common_encryptor:
        type: AES
        props:
          aes-key-value: d6oadClrrb9A3GWo
props:
  sql-show: true

缓存穿透解决

缓存穿透是指在使用缓存系统时,恶意或频繁地请求一个不存在于缓存中的数据,导致每次请求都需要查询数据库或其他数据存储系统,从而绕过了缓存的效果,严重影响系统性能。这种情况通常发生在恶意攻击、大量请求缓存中不存在的数据或缓存数据过期后的高并发访问。

缓存穿透会导致以下问题:

1. 频繁的查询数据库或其他数据存储系统,增加了数据库负载,降低了系统的吞吐量。

2. 大量的缓存不存在的数据请求可能会导致缓存服务器的内存被耗尽,影响其他正常的缓存操作。

3. 用户体验下降,因为请求的数据无法从缓存中获取,导致响应时间延长。

采用布隆过滤器结合缓存的方式来解决缓存穿透问题

用户注册接口

用户注册接口整体流程如下所示:

责任链模式

12306 系统中,我们定义责任链模式分为三步,确定方法执行入参、定义当前业务责任链接口以及具体实施验证责任链执行器。

1)确定方法执行入参

因为我们是用户注册接口,验证的也是用户提交的数据,直接复用该实体即可。

@Data
public class UserRegisterReqDTO {

    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;

    /**
     * 真实姓名
     */
    private String realName;

    /**
     * 证件类型
     */
    private Integer idType;

    /**
     * 证件号
     */
    private String idCard;

    /**
     * 手机号
     */
    private String phone;

    /**
     * 邮箱
     */
    private String mail;

    /**
     * 旅客类型
     */
    private Integer userType;

    /**
     * 审核状态
     */
    private Integer verifyState;

    /**
     * 邮编
     */
    private String postCode;

    /**
     * 地址
     */
    private String address;

    /**
     * 国家/地区
     */
    private String region;

    /**
     * 固定电话
     */
    private String telephone;
}

2)定义业务责任链接口

public interface UserRegisterCreateChainFilter<T extends UserRegisterReqDTO> extends AbstractChainHandler<UserRegisterReqDTO> {

    @Override
    default String mark() {
        return UserChainMarkEnum.USER_REGISTER_FILTER.name();
    }
}

3)定义责任链业务具体处理器。

在定义责任链处理器时,需要注意使用  getOrder 排序接口来决定组件的执行顺序。通常情况下,处理效率高且在内存中执行的验证策略应该优先执行,而需要涉及交互操作(例如 Redis 等)的处理策略则放在后面执行。

举例来说,假设用户没有传递身份证号,在这种情况下,首先执行验证用户名的操作是非常浪费的,因为后续还需要验证参数必填性,这样就多了一次查询缓存的无用耗时。尽管性能损耗可能不会很高,但这种无用的损耗应该尽量避免。

因此,通过合理地使用  getOrder 排序接口,我们可以优化责任链的执行顺序,使得处理效率高的操作优先执行,避免不必要的性能损耗,从而提升整体处理性能和效率。

用户表相关新增

先来查看 12306 登录功能的原型截图及其对应的功能

在登录功能中,用户一栏明确标出可以使用用户名、邮箱或手机号中的任意一个搭配密码进行登录。需要强调的是,在分库分表中,我们是通过用户名进行分片的。因此,如果在查询用户信息时不带用户名,将会触发读扩散问题。

为了解决这个问题,我们引入了两张路由表:用户手机号表和用户邮箱表。这些表的核心字段是手机号和邮箱,以及它们对应的用户名。通过这样的设计,我们能够在用户登录时,灵活地使用手机号、邮箱或用户名来进行认证。

 其它操作

在用户注册后,该用户名将不再可用,因此我们需要将其添加到布隆过滤器中,以防止其他人在后续尝试注册时再次使用。

另外,关于用户注册文章中提到的用户名可复用问题,我们特别考虑了这一点。已经注销的用户名需要能够被其他用户再次使用,因此我们对可复用用户名进行了扩展设计。

这意味着,我们需要将对应的缓存和数据库表一并删除。一旦删除完成,后续用户将无法再通过这个扩展点使用该用户名。这样的设计保证了用户名的合理复用,同时确保已注销用户名的信息不会对后续用户产生影响。

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

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

相关文章

我们和openAi的差距,只差向神祈祷了?

这两天看到了两张挺有意思的图片&#xff0c;关于openAi研究人员和qianWen的研究人员的日常生活作息表。蛮有意思&#xff0c;看到后有很多感想&#xff0c;特地分享出来。&#xff08;声明&#xff1a;对比没有恶意&#xff0c;也没有好坏之分。他们本都是站在金字塔最顶尖的人…

StarRocks——滴滴OLAP的技术实践与发展方向

原文大佬的这篇StarRocks实践文章整体写的很深入&#xff0c;介绍了StarRocks数仓架构设计、物化视图加速实时看板、全局字典精确去重等内容&#xff0c;这里直接摘抄下来用作学习和知识沉淀。 目录 一、背景介绍 1.1 滴滴OLAP的发展历程 1.2 OLAP引擎存在的痛点 1.2.1 运维…

AI人工智能芯片制作研究与开发技术资料(三百多份文档)【机×密】

收藏多年的精品&#xff0c;不可多得的东西。对芯片开发研究有兴趣同学&#xff0c;赶快下载看看吧。文件大小3G多。 AI人工智能芯片制作研究与开发技术资料&#xff08;三百多份文档&#xff09;【机密】 下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/14Duh…

【网络安全】SQL注入_sql注入攻击实例(网安人必学系列)

1.1 .Sql注入攻击原理 SQL注入漏洞可以说是在企业运营中会遇到的最具破坏性的漏洞之一&#xff0c;它也是目前被利用得最多的漏洞。要学会如何防御SQL注入&#xff0c;首先我们要学习它的原理。 针对SQL注入的攻击行为可描述为通过在用户可控参数中注入SQL语法&#xff0c;破…

容器镜像详解

1. 镜像组成 一个标准的OCI容器镜像由index, manifest, config, image layers这几个部分组成。 以docker镜像为例&#xff0c;下载的镜像文件保存在/var/lib/docker/目录下面 image/overlay2子目录下面保存着镜像相关的一些元数据 在下面的介绍主要以nginx:latest镜像为例子…

Django定时任务之django_apscheduler使用

Django定时任务之django_apscheduler使用 今天在写一个任务需求时需要用到定时任务来做一部分数据处理与优化&#xff0c;于是在了解完现有方法&#xff0c;结合自己需求决定使用django_apscheduler&#xff0c;记录一下过程&#xff0c;有几篇值得参考的文章放在结尾&#xf…

超详细!彻底说明白Redis持久化

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 微信公众号&#xff1a;Java随想录 文章目录 Redis持久化方式RDBfork 函数与写时复制RDB 相关配置 AOFAOF 文件解读AOF 的写入与同步AOF 重写AOF重写的实现AOF 重写面临的问题AOF重写缓存区 AOF相关配置AOF …

【深入了解设计模式】适配器设计模式

适配器设计模式 适配器设计模式是一种结构型设计模式&#xff0c;用于将一个类的接口转换成客户端所期望的另一个接口&#xff0c;从而使得原本由于接口不兼容而不能一起工作的类能够一起工作。适配器模式通常用于以下场景&#xff1a; 现有接口与需求不匹配&#xff1a;当需要…

Escalate_Linux(4)-利用SUDO实现提权

利用SUDO实现提权 利用用户的sudo授权获得root的shell cat /etc/passwd cat /etc/sudoers 命令没有权限 echo "cat /etc/sudoers" >/tmp/ls chmod 755 /tmp/ls export PATH/tmp:$PATH /home/user5/script 想办法更改user1的口令 echo echo "user1:xiao…

【C语言基础】:操作符详解(一)

文章目录 操作符详解1. 操作符的分类2. 二进制和进制转换2.1 什么是二进制、八进制、十进制、十六进制2.1.1 二进制和进制转换2.1.2 二进制转十进制2.2.3 二进制转八进制2.2.4 二进制转十六进制 3. 源码、反码、补码4. 移位操作符4.1 左移操作符4.2 右移操作符 5. 位操作符&…

协议的概念+本质+作用+最终表现形式,网络问题(技术+应用+解决的协议+存在原因),主机的对称性

目录 协议 概念 示例 -- 摩斯密码 本质 作用 网络问题 引入 技术问题 应用问题 主机的对称性 问题对应的协议 问题出现的原因 理解协议(代码层面) 举例 -- 快递单 协议的最终表现形式 协议被双方主机认知的基础 协议 概念 协议是在计算机通信和数据传输中规定通…

Seata Server 服务搭建

概述 Seata 分布式事务需要 Seata Seaver 支持&#xff0c;Seata Server在 架构中扮演着 事务管理器的角色。Seata 服务需要往 Nacos 注册中心注册、以及读取配置文件&#xff0c;因此 Seata 启动前需要部署 Nacos 环境。 安装包下载 下载地址: https://download.csdn.net/dow…

【Redis学习笔记03】Java客户端

1. 初识Jedis Jedis的官网地址&#xff1a;https://github.com/redis/jedis 1.1 快速入门 使用步骤&#xff1a; 注意&#xff1a;如果是云服务器用户使用redis需要先配置防火墙&#xff01; 引入maven依赖 <dependencies><!-- 引入Jedis依赖 --><dependency&g…

CSS 的圆角矩形

CSS 的圆角矩形 通过 border-radius 属性使矩形边框带圆角效果成为圆角矩形 语法&#xff1a;border-radius: length; length 是内切圆的半径&#xff0c;其数值越大, 弧线越明显 border-radius 属性值描述length定义圆角的形状%以百分比定义圆角的形状 生成圆形 让 border-…

英伟达狂飙,上演大象坐火箭

英伟达市值破 2W 亿 这两天全球资本市场最大的事情就是英伟达&#xff08;NVDA&#xff09;公布了财报。 本来市场&#xff08;分析师&#xff09;的预期就高&#xff0c;结果财报公布比预期还要高出不少。 NVDA 直接上演「大象坐火箭」&#xff0c;在财报公布后的第一个交易日…

Spring Cloud Gateway官方文档学习

文章目录 推荐写在前面一、熟悉Gateway基本概念与原理1、三大概念2、工作流程 二、基本使用路由断言的两种写法 三、路由断言工厂1、After路由断言工厂2、Before路由断言工厂3、Between路由断言工厂4、Cookie路由断言工厂5、Header路由断言工厂6、Host路由断言工厂7、Method路由…

[C++]18:set和map的使用

set和map的使用 一.关联式容器&#xff1a;1.简单概念&#xff1a;2.<key , value>--->键值对3.set和map的底层结构&#xff08;平衡搜索树或者红黑树&#xff09; 二.set1.set (排序不重复)1.模板参数&#xff1a;2.set是一个有序存储的容器&#xff1a;3.set中每个数…

STL常用容器(string容器)---C++

STL常用容器目录 1.string容器1.1 string基本概念1.2 string构造函数1.3 string赋值操作1.4 string字符串拼接1.5 string查找和替换1.6 string字符串比较1.7 string字符存取1.8 string插入和删除1.9 string子串 1.string容器 1.1 string基本概念 本质&#xff1a; string是C…

Peter算法小课堂—动态规划

Peter来啦&#xff0c;好久没有更新了呢 今天&#xff0c;我们来讨论讨论提高组的动态规划。 动态规划 动态规划有好多经典的题&#xff0c;有什么背包问题、正整数拆分、杨辉三角……但是&#xff0c;如果考到陌生的题&#xff0c;怎么办呢&#xff1f;比如说2000年提高组的…

计算机网络:思科实验【2-MAC地址、IP地址、ARP协议及总线型以太网的特性】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;Cisco Packet Tracer实验 本文对应的实验报告源文件请关注微信公众号程序员刘同学&#xff0c;回复思科获取下载链接。 实验目的实验环境实验内容MAC地址、IP地址、ARP协议总线型以太网的…