学成在线- 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 优势
- 低协议开销、低功耗、数百万设备连接、推送通知。