目录
- 多应用实例全局唯一订单号
- 分库分表&扩容问题
- 订单C端查询&B端查询&保存
- 订单缓存设计&3万+qps
- 订单配置中心
- 订单状态机
- 订单熔断&降级
内容
- 多应用实例全局唯一订单号(按时间趋势递增,订单id带有业务标示)
xx-snowflake简介
改造版 xx-snowflake方案采用“1+5+41+5+12”的方式组装ID号,使用Zookeeper持久顺序节点的特性自动对snowflake节点配置wokerID。 xx-snowflake是按照下面几个步骤启动的:
- 启动Leaf-snowflake服务,连接Zookeeper,在leaf_forever父节点下/snowflake/order-center/forever/检查自己是否已经注册过(是否有该顺序子节点)。(workerid:/snowflake/order-center/forever/192.168.17.197:2181-0000000000)
- 如果有注册过直接取回自己的workerID(zk顺序节点生成的int类型ID号),启动服务。
- 如果没有注册过,就在该父节点下面创建一个持久顺序节点,创建成功后取回顺序号当做自己的workerID号,启动服务。
xx-snowflake优点
- 基于snowflake算法订单号趋于递增
- 固定17位+2位业务标示。订单业务标示占据低2位。
- xx-snowflake对Zookeeper生成机器号做了弱依赖处理,即使Zookeeper有问题,也不会影响服务。Leaf在第一次从Zookeeper拿取workerID后,会在本机文件系统上缓存一个workerID文件。即使ZooKeeper出现问题,同时恰好机器也在重启,也能保证服务的正常运行。这样做到了对第三方组件的弱依赖,一定程度上提高了SLA。
- 订单id生成规则不容易破解。防止黑客根据算法算到公司的一天的承单量。
2.分库分表&扩容问题
垂直分库分表
按照业务拆分的方式称为垂直分片,又称为纵向拆分,它的核心理念是专库专用。 在拆分之前,一个数据库由多个数据表构成,每个表对应着不同的业务。而拆分之后,则是按照业务将表进行归类,分布到不同的数据库中,从而将压力分散至不同的数据库。 下图展示了根据业务需要,将用户表和订单表垂直分片到不同的数据库的方案。
垂直分片往往需要对架构和设计进行调整。通常来讲,是来不及应对互联网业务需求快速变化的;而且,它也并无法真正的解决单点瓶颈。 垂直拆分可以缓解数据量和访问量带来的问题,但无法根治。如果垂直拆分之后,表中的数据量依然超过单节点所能承载的阈值,则需要水平分片来进一步处理。
ps:垂直分片常见的分片规则以时间维度分表策略
分库分表规则
目前采用的是sharding-jdbc的PreciseShardingAlgorithm,用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用。
分库规则: user_id%数据源个数
分表规则: user_id/数据源个数 % 表个数
分库分表扩容
扩容步骤:
1)等待ds_0_主和ds_1_主的数据同步到其备服务器,即ds_0_从和ds_1_从。
2)停止写服务,等待主备完全同步后解除ds_0_主与ds_0_从、ds_1_主与ds_1_从之间的主备关系。
3)修改中间层的映射规则。
4)开启写服务,用户id哈希值模4等于0、1、2、3的数据将分别写入到ds_0、ds_1、ds_2、ds_3。
5)分别给ds_0、ds_1、ds_2、ds_3增加从库。
【问题】我们为什么要选择走按用户维度做为分片键,而不是从订单维度来做?
- 对于C端用户来说,用户都是在登录之后,再去查询订单,按用户维度分片之后,相同用户的订单数据,都会落到同一个数据库的同一个表中,
这样用户查询自己的订单的时候,可以不用跨库操作,减轻服务压力。
- 对以后跟用户中心做交互的时候,都从用户的角度来做,对接起来会比较容易
- 对于toB和toG的多维多查询来说,我们可以在es中建立一层映射关系来应对。
3.订单C端查询&B端查询&保存
c端用户查询逻辑
B端用户查询逻辑
4.redis缓存处理流程图
读缓存处理流程图
写缓存处理流程图
redis&db数据一致性保证
循环2次更新缓存操作,直到更新成功退出循环,这一步主要能减小由于网络瞬间抖动导致的更新缓存失败的概率。对于缓存接口长时间不可用,靠循环调用更新接口是不能补救接口调用失败的。如果循环2次还没有更新成功,发送redis更新失败埋点
缓存代码示例
获取订单详情(读更新缓存)
更新or同步订单(更新订单refresh订单缓存)
5.订单配置中心
添加Apollo客户端依赖
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.6.0</version>
</dependency>
application.yml添加以下配置
app-id: apollo创建项目时的appid
apollo.meta: meta-server地址,一般同config-server地址
apollo.bootstrap.namespaces: 使用配置的命名空间,多个以逗号分隔
ps: 我们会在打包的时候替换#param#如下设置
apollo具体安装详见: https://gitee.com/lepdou/apollo/
<重要提示>原文链接