学成在线- 6分片上传,8xxl-job
课程模块开发 分布式事务,消息表
spring-security oauth 用户认证授权 学成在线
学成在线认证授权 一些代码
黑马分布式事物
框架学习 - 若依 / RuoYi-Vue-Plus
统一数据权限
若依数据权限使用
数据权限表结构
1. 设备故障 描述 负载均衡 消费消息
- 负载均衡的策共享队列模式订阅EMQ中的售货机状态消息,当设备为故障状态的时候,创建一个自动维修工单。
2.xxl-job 分片广播
3.解析设备上传指标报文,进行设备报警状态判断
eqm 接收设备报文信息。
- 解析设备信息。
- 保存报文信息
- 保存设备信息
- 指标透传(
设备的指标信息),传递到其他服务,进行业务逻辑处理。
3.1 订阅所有指标配置的主题

l

3.2 达到报警状态后,进行透传(外部系统)
3.3 web hook 监控设备是否在线

通过emqx 中的web hook ,设备断开连接,执行回调函数,发送到服务器。
根据设备id 设置设备的 online status
3.4 通过emqx 代理订阅解决精准操控每个设备
emqx服务器配置代理主题,客户端连接上emqx就可以通过配置%c(客户端id),设备即可通过代理订阅方式,订阅主题。设备通过指定的主题发送客户端id到emqx。后台订阅主题,将客户端信息,和设备信息绑定。
4. influx db 保存设备报文信息。
influx db 主要用来存储一些时间序列的数据。(按时间维度索引的数据)
物联网设备发送过来的报文指标信息,存入influx db中
设备很多,传输过来的报文也很多。
- 高并发写入,不需要更新。
- 数据压缩存储。
- 低延时查询。
| InfuxDB中的概念 | 传统数据库概念 |
|---|---|
| database | 数据库 |
| measurement | 数据库中的表 |
| point | 表中的行 |
Point是由时间戳(time)、标签(tags)、数据(fields)三部分组成,具体的含义如下:
| point属性 | 含义 |
|---|---|
| time | 数据记录的时间,主索引,默认自动生成,相当于每行数据都具备的列 |
| tags | 相当于有索引的列。tag中存储的值的类型是字符串类型 如果需要检索就 是tags |
| fields | value值,没有索引的列。field中存储的值得类型:字符串、浮点数(Double)、整数、布尔型。一个field value总是和一个timestamp相关联 如果查询是就是这个值,就用fields |

上面的截图展示了在名字是test的measurement存储的一些数据,我们可以通过常规的sql语句查询到这些数据。这些测试数据是在一定时间内产生的温度指标数据,其中每行数据包含了具体产生的时间(time)、是否告警(alarm)、设备编号(deviceId)、告警级别(level)、指标名称(quotaName)、数值单位(unit)、指标数值(value)。
其中value列就是filed,里面存储的是Integer;time列是每条记录产生的时间;其余列都是tag,存储的数据都是字符串。
# hostname=server01 是索引列,继续添加索引列就使用逗号。 service 也是tag列
insert disk_free,hostname_ss1,service=app value=2222i
insert disk_free,hostname=server01 value=442221834240i
# tags 不用加引号,因为只能是字符串。
insert disk_free,hostname=server01 value=442221834240i,sv="aaaa"
sv 是filed类型,加引号,要识别是field 的字符串类型
其中 disk_free 就是表名,hostname是索引(tag),value=xx是记录值(field),记录值可以有多个,系统自带追加时间戳
4.1 influx db 存储引擎
retention policy 存储策略。 保存数据的时间
shard 分片
- Cache 缓存
- WAL 写优化的存储格式,持久化
- TSM file
- Compactor
存储目录
influxdb的数据存储有三个目录,分别是meta、wal、data:
- meta 用于存储数据库的一些元数据,meta 目录下有一个 meta.db 文件;
- wal 目录存放预写日志文件,以 .wal 结尾;
用于写的 - data 目录存放实际存储的数据文件,以 .tsm 结尾。
用于查询的
4.2 influx db 保存设备的上报信息
设备通过eqm x 上报设备报文数据,服务端接收数据保存到influx db中。
4.3 通过influx db 查询设备的报文信息
4.4 设备详情信息查询 influx db+mysql
5.设备报表分析
5.1 设备状态统计 饼图
5.2 异常告警趋势表 折线图 使用time() 函数。
这里需要说明的是:
在要执行的sql里的group by分组里使用了InfluxDB的time时间函数
- group by time(1m):按每分钟进行分组汇总
- group by time(1h):按每小时进行分组汇总
- groupby time(1d):按每天进行分组汇总
之后配合select中的count函数就可以获取到具体时间维度里汇总里的总数了,这样就能获取到我们想要的汇总数据了。
InfluxDB除了会根据sql语句返回pointValue也会同时返回每一条数据对应的time时间列。

5.3 柱状图 报警 top 10
top() 函数
6. 保存设备经纬度 redis geo
6.1 设备上报gps 信息存储到redis 中
6.2 沉默周期 redis 实现
告警透传,同样的告警,在沉默周期内不在重复提示告警。
redis 实现
String 类型,key 为设备id,过期时间为5minutes,存在就不再进行告警。
7. 报警离线设备前端推送 通过emqx web hook 监控设备在线
EMQ的webHook来实现实现设备断网监控,并更新设备状态。
webhook由emqx_web_hook插件提供的,将EMQ X中的钩子事件(连接,断开)通知到某个Web服务的功能
告警信息推送到emqx,前端订阅消费。
7.1 mybatis 整合redis 二级缓存
设备信息,设备指标信息。
8. 项目亮点
8.1 功能模块
- 报警沉默周期
8.2 项目亮点
- 使用策略模式、工厂模式优化接收设备上报数据。注解
9 oauth 密码模式
9.1 认证流程


执行流程:
1、用户登录,请求认证服务
2、认证服务认证通过,生成 jwt 令牌,将 jwt 令牌及相关信息写入 Redis,并且将身份令牌写入 cookie
3、用户访问资源页面,带着 cookie 到网关
4、网关从 cookie 获取 token,并查询 Redis 校验 token,如果 token 不存在则拒绝访问,否则放行
5、用户退出,请求认证服务,清除 redis 中的 token,并且删除 cookie 中的 token
使用 redis 存储用户的身份令牌有以下作用:
1、实现用户退出注销功能,服务端清除令牌后,即使客户端请求携带 token 也是无效的。
2、由于 jwt 令牌过长,不宜存储在cookie中,所以将jwt的 身份令牌 存储在 redis,客户端请求服务端时附带这个 身份令牌,服务端根据身份令牌到 redis 中取出身份令牌对应的 jwt 令牌。
9.2 网关功能
- 路由转发
- jwt认证
- 白名单
10. 最终数据一致性 分布式事物
本地消息表+任务调度方式。实现分布式事物最终数据一致性。
10.1 熔断降级
熔断是当下游服务异常时一种保护系统的手段,降级是熔断后上游服务处理熔断的方法。

10.2 消息可靠性、幂等性、消息堆积。
消息可靠性、幂等性、消息堆积。
10.3 基于spring 事物的扩展
spring 事物原理
一个方法上加了@transaction注解,执行方法时,开启事物。
开启事物的时候,创建数据库连接,
编写可靠事物代码。
通过spring 声明式事务,多种情况下会失效。
- 方法内调用。没有经过bean 的代理无法aop增强,进行事物控制。
- 在方法里面启动异步线程,异步线程拿到的连接和主线程拿到的连接不是同一个。所以控制不了异步线程的事物。
- 发送
锁释放,没提交。导致事物失效,提交事务后,在释放锁。
// demo
/**
* @author hyp
* @date 2023/5/24
*/
public class TransactionDemo {
@Transactional
public void doTx() {
// start tx
//当前上下文事物执行完后,执行下面回调方法
TransactionUtils.doAfterTransaction(() -> {
//send mq rpc
});
// end tx
}
}
// 工具类
/**
* 本地事物提交后 回方法工具类
* TranscationSynazation
* @author hyp
* @date 2023/5/24
*/
public class TransactionUtils {
public static void doAfterTransaction(Runnable runnable){
//判断当前上下文是否由事物激活
if(TransactionSynchronizationManager.isActualTransactionActive()){
// 注册当前事务上下文同步器
TransactionSynchronizationManager.registerSynchronization(new TransactionCompletion(runnable));
}
}
}
class TransactionCompletion implements TransactionSynchronization{
private Runnable runnable;
public TransactionCompletion(Runnable runnable) {
this.runnable = runnable;
}
/**
* int STATUS_COMMITTED = 0;
* int STATUS_ROLLED_BACK = 1;
* int STATUS_UNKNOWN = 2;
* @param status 事物状态
*/
@Override
public void afterCompletion(int status) {
if(status==TransactionSynchronization.STATUS_COMMITTED){
// 事物成功提交后才执行回
//回调函数,
runnable.run();
}
}
}
10.4 多线程导入 控制事物
多线程控制事物
10.5 分片上传
10.5.1 文件分片
-
先把整个大文件md5生成,检查是是否已经上传过。(MD5 文件)
判断数据库有,文件服务器有才不上传。 -
对分块文件上传前检查 是否存在 文件服务器目录**(md5前2位/md5 3-4位/md5名 目录)** md5 前4位 做2个子目录 ,chunk 存 分块 (接口 MD5,分块文件 序号)

-
上传分块 (MD5 ,分块序号,分块文件)
-
合并文件 (MD5 ,分块总数,文件名称)
合并文件
校验文件服务器合并后的MD5 和上传的MD5是否一致
文件信息入库
清除分块文件
10.6 上传文件事物失效
在上传文件到文件存储服务器后,准备把文件信息入库。
非事物方法 直接调用事物方法( 并不是以代理对象调用)
upload方法 调用了本类的 信息入库的方法,upload方法没有事物,导致 信息入库方法的事物失效。
10.6.1 事物失效
- 调用事物方法,把异常捕获了,导致事物失效
- 非事物方法调用 事物方法
- 非public 方法
- rollbackFor 回滚异常 和 抛出异常不匹配
10.6.2 mybatis 分页插件原理
首先分页参数放在ThreadLocal中,拦截执行的sql,根据数据库的类型添加对应的sql语句。
计算出了 total总条数,pageNum当前第几页,pageSize 等数据。
10.6.3 #{} 和${} 的区别
#{} 是一个占位符,解析为SQL时,会将形参变量的值取出,并自动给其添加引号。
${} 解析为SQL时,将形参变量的值直接取出,直接拼接显示在SQL中
常见的使用${}的情况:
1.当sql中表名是从参数中取的情况
2.order by排序语句中,因为order by 后边必须跟字段名,这个字段名不能带引号,如果带引号会被识别会字符串,而不是字段。
11 京东云技术文章
-----------------线上问题--------------
线上问题处理案例:出乎意料的数据库连接池 | 京东云技术团队
Redis缓存的主要异常及解决方案
------------------mybatis---------
源码学习之MyBatis的底层查询原理 | 京东云技术团队
Mybatis的parameterType造成线程阻塞问题分析 | 京东云技术团队
------------------------------------并发编程------
关于并发编程与线程安全的思考与实践 | 京东云技术团队–synchronized
架构师日记-从代码到设计的性能优化指南 | 京东云技术团队
JAVA多线程并发编程-避坑指南
rt下降40%?程序并行优化六步法 | 京东云技术团队
------------------------------模式-----------------------
1分钟学会、3分钟上手、5分钟应用,快速上手责任链框架详解 | 京东云技术团队
烂怂if-else代码优化方案 | 京东云技术团队
---------------------------返回结果----------------------
一站式统一返回值封装、异常处理、异常错误码解决方案—最强的Sping Boot接口优雅响应处理器 | 京东云技术团队
如何优雅的处理异常
--------------------------------jvm-------------------------------
线上FullGC问题排查实践——手把手教你排查线上问题
谈JVM参数GC线程数ParallelGCThreads合理性设置
jvm中类和对象定义存储基础知识 | 京东云技术团队
源码剖析JVM类加载机制
从原理聊JVM(一):染色标记和垃圾回收算法
线上FullGC问题排查实践——手把手教你排查线上问题
------------事务、幂等--------------------
幂等设计详解 | 京东云技术团队
如何实现数据库读一致性 | 京东云技术团队
如何在微服务下保证事务的一致性 | 京东云技术团队
------------redis-----
Redis缓存高可用集群
缓存空间优化实践
Redis数据结构(一)-Redis的数据存储及String类型的实现
京东云开发者|Redis数据结构(二)-List、Hash、Set及Sorted Set的结构实现
-----mysql-----------
一文了解MySQL中的多版本并发控制
一文带你搞懂如何优化慢SQL
记录一次数据库CPU被打满的排查过程
这个 MySQL bug 99% 的人会踩坑!
MySQL性能优化浅析及线上案例
深入理解MySQL索引底层数据结构
【实践篇】教你玩转JWT认证—从一个优惠券聊起 | 京东云技术团队
12 观察者模式、策略模式
12.1 观察者模式
多个对象间,存在一对多的依赖关系,当一个对象的状态发生关系时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时候又被称为发布订阅模式, spring 事件机制。
12.2 观察者模式、动态策略路由
不同事件业务触发的情况下,会去通知用户邮件、短信、推送等。不同的事件,不同的业务场景下,可能时不同的推送组合,通知用户。
首先就是通过 不同业务场景 if else 判断 应该调用哪几个。
改进:
通过观察者模式,让事件的发生和通知分开处理,在代码上进行解耦。
接着,关于每种业务场景,有哪几种通知,又抽取了策略模式的接口,动态的组合每一种业务需要对应哪些通知类型。后期更灵活之后,把业务,通知组合可以放到配置中心区,达到的效果,如果需要新增业务,只需要改一下配置中心的配置,就能够组合不同的通知的模式。进行通知。 从而更加解耦,更有扩展性。
通过温度,湿度,电压,获取对应的level。根据level,通过策略模式在map中获取发送消息组合的list。
遍历所有发送消息实现类,判断是否在以上获取到的消息组合集合中。
12.3 通过 自定义注解、工厂模式+策略模式,进行项目接收mqtt消息代码解耦,提高扩展性。
12.4 通过redis,Zset数据结构,定时任务,解决了处理设备上报故障状态接口运行效率低下,查询逻辑复杂问题。使得总体接口性能提升20%,使用 Set 结构来防止缓存中存放重复订单
(1)使用redis来保存每个人的工单数据,每次创建工单在redis里使用原子增,不用考虑锁。这样得到每日最低工单人员的查询可以做到对数据库零查询。
(2)使用redis的ZSet可以实现数据的自动排序,无需手动排序,再次提升了程序的运行效率,降低了代码的复杂度。
(3)key的规则,以固定字符串(前缀)+时间+区域+工单类别(运营/运维)为大key,以人员id做小key,过期时间为2天。
(4)redis工单数列表初始化,由xxl-job负责处理,每日下午生成第2天的工单数列表。
12.5 通过本地消息表+Rabbitmq+xxl-job方式,保证添加考试计划事物的最终一致性。
12.6 mqtt vs http
mqtt 以数据为中心,而http是以文本为中心。http 是应用于服务端、客户端请求响应协议。mqtt 是轻量级的(将数据作为二进制字节数组传输)和发布订阅的模型。适用于资源受限的设备,有助于节省带宽。
发布订阅模式,可以进行解耦。(发布者和订阅者的解耦)不需要直接建立联系,无需等待。
- 功能简洁,低功耗。
- 发布订阅模式。
- 传输量低,节省带宽,提高传输效率。
http 使用使用受限。
- 实现成本高,实时性差。(设备主动服务器发送数据,只能应用于数据采集,服务端无法主动发消息给客户端)
- 安全性不高 http 是明文协议。https。
- 设备受限。 需要实现http协议,XML/JSON数据格式的解析。
mqtt 优势
- 低协议开销、低功耗、数百万设备连接、推送通知。



















