第378集设备服务接入系统Java微服务后端架构实战


  • Java

  • 微服务

  • 设备接入

  • MQTT

  • 物联网

  • SpringBoot categories:

  • 后端开发 keywords: 设备服务接入系统,微服务架构,Java实战,设备接入,MQTT,设备注册,设备认证,设备连接管理,设备指令下发,设备数据上报,SpringBoot description: 深入解析设备服务接入系统的Java微服务架构设计,从设备注册认证、MQTT连接管理、设备指令下发、设备数据上报到心跳检测和状态管理,提供完整的企业级设备接入解决方案


设备服务接入系统Java微服务后端架构实战

1. 架构概述

设备服务接入系统是IoT平台的核心基础设施,需要支持海量设备的接入、认证、连接管理、指令下发和数据上报。本篇文章将深入讲解如何基于Java微服务架构实现一个高性能、高可用、可扩展的设备服务接入系统。

1.1 系统架构图

go 复制代码
物理设备 → 接入网关 → 设备服务 → 数据库/缓存
          ↓
     设备注册/认证
          ↓
     建立连接(MQTT/WebSocket)
          ↓
     心跳检测
          ↓
     设备指令下发
          ↓
     设备数据上报
          ↓
     设备状态管理

设备服务 → 消息队列 → 业务服务
          ↓
     设备数据转发
          ↓
     设备事件通知

1.2 核心组件

  • 接入网关(Access Gateway):负责设备连接接入、协议解析、消息路由

  • 设备服务(Device Service):负责设备注册、设备认证、设备管理、设备状态维护

  • MQTT Broker:负责MQTT协议连接管理和消息转发

  • 设备连接管理器(Device Connection Manager):负责设备连接状态管理、心跳检测

  • 设备指令服务(Device Command Service):负责设备指令下发、指令状态跟踪

  • 设备数据服务(Device Data Service):负责设备数据接收、数据解析、数据转发

  • 数据库(MySQL):持久化设备信息、设备连接记录、设备指令记录

  • 缓存(Redis):缓存设备连接状态、设备在线状态、设备会话信息

  • 消息队列(Kafka/RocketMQ):异步处理设备数据、设备事件通知

2. 接入网关服务实现

2.1 MQTT接入网关核心代码

go 复制代码
/**
 * MQTT接入网关
 * 负责设备MQTT连接接入、协议解析、消息路由
 */
@Component
@Slf4j
public class MqttAccessGateway {

    @Autowired
    private DeviceServiceClient deviceServiceClient;
    
    @Autowired
    private DeviceConnectionManager deviceConnectionManager;
    
    @Autowired
    private DeviceCommandService deviceCommandService;
    
    @Autowired
    private DeviceDataService deviceDataService;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    /**
     * 处理设备连接请求
     * 流程:设备连接 → 设备认证 → 建立连接 → 注册设备连接
     */
    public MqttConnectResult handleConnect(MqttConnectMessage message, Channel channel) {
        try {
            String clientId = message.payload().clientIdentifier();
            String username = message.payload().userName();
            String password = message.payload().passwordInBytes() != null ? 
                    new String(message.payload().passwordInBytes()) : null;
            
            // 1. 设备认证
            DeviceAuthResult authResult = deviceServiceClient.authenticateDevice(
                    clientId, username, password);
            
            if (!authResult.isSuccess()) {
                log.warn("设备认证失败: clientId={}, username={}, reason={}", 
                        clientId, username, authResult.getMessage());
                return MqttConnectResult.failed(authResult.getMessage());
            }
            
            // 2. 注册设备连接
            DeviceConnection connection = deviceConnectionManager.registerConnection(
                    clientId, channel, authResult.getDeviceInfo());
            
            // 3. 更新设备在线状态
            updateDeviceOnlineStatus(clientId, true);
            
            // 4. 发送设备上线事件
            sendDeviceOnlineEvent(authResult.getDeviceInfo());
            
            log.info("设备连接成功: clientId={}, deviceId={}, deviceType={}", 
                    clientId, authResult.getDeviceInfo().getDeviceId(), 
                    authResult.getDeviceInfo().getDeviceType());
            
            return MqttConnectResult.success(connection);
            
        } catch (Exception e) {
            log.error("处理设备连接失败: error={}", e.getMessage(), e);
            return MqttConnectResult.failed("设备连接处理失败: " + e.getMessage());
        }
    }

    /**
     * 处理设备断开连接
     */
    public void handleDisconnect(String clientId, Channel channel) {
        try {
            // 1. 移除设备连接
            deviceConnectionManager.removeConnection(clientId, channel);
            
            // 2. 更新设备离线状态
            updateDeviceOnlineStatus(clientId, false);
            
            // 3. 发送设备离线事件
            DeviceInfo deviceInfo = deviceServiceClient.getDeviceInfo(clientId);
            if (deviceInfo != null) {
                sendDeviceOfflineEvent(deviceInfo);
            }
            
            log.info("设备断开连接: clientId={}", clientId);
            
        } catch (Exception e) {
            log.error("处理设备断开连接失败: clientId={}, error={}", 
                    clientId, e.getMessage(), e);
        }
    }

    /**
     * 处理设备发布消息(数据上报)
     */
    public void handlePublish(String clientId, String topic, MqttPublishMessage message) {
        try {
            // 1. 解析设备数据
            byte[] payload = message.payload().array();
            DeviceData deviceData = parseDeviceData(clientId, topic, payload);
            
            // 2. 更新设备心跳时间
            updateDeviceHeartbeat(clientId);
            
            // 3. 处理设备数据
            deviceDataService.processDeviceData(deviceData);
            
            log.debug("处理设备数据上报: clientId={}, topic={}, dataSize={}", 
                    clientId, topic, payload.length);
            
        } catch (Exception e) {
            log.error("处理设备数据上报失败: clientId={}, topic={}, error={}", 
                    clientId, topic, e.getMessage(), e);
        }
    }

    /**
     * 处理设备订阅请求
     */
    public void handleSubscribe(String clientId, MqttSubscribeMessage message) {
        try {
            // 1. 验证订阅权限
            List<MqttTopicSubscription> subscriptions = message.payload().topicSubscriptions();
            for (MqttTopicSubscription subscription : subscriptions) {
                String topic = subscription.topicName();
                if (!validateSubscribePermission(clientId, topic)) {
                    log.warn("设备订阅权限不足: clientId={}, topic={}", clientId, topic);
                    continue;
                }
                
                // 2. 记录订阅关系
                recordSubscription(clientId, topic);
            }
            
            log.info("设备订阅成功: clientId={}, subscriptions={}", 
                    clientId, subscriptions.size());
            
        } catch (Exception e) {
            log.error("处理设备订阅失败: clientId={}, error={}", 
                    clientId, e.getMessage(), e);
        }
    }

    /**
     * 下发设备指令
     */
    public void sendDeviceCommand(String clientId, DeviceCommand command) {
        try {
            // 1. 获取设备连接
            DeviceConnection connection = deviceConnectionManager.getConnection(clientId);
            if (connection == null || !connection.isActive()) {
                throw new BusinessException("设备未连接: " + clientId);
            }
            
            // 2. 构建MQTT消息
            String topic = buildCommandTopic(clientId, command.getCommandType());
            MqttPublishMessage mqttMessage = buildMqttPublishMessage(topic, command);
            
            // 3. 发送MQTT消息
            connection.getChannel().writeAndFlush(mqttMessage);
            
            // 4. 记录指令下发
            deviceCommandService.recordCommandSent(clientId, command);
            
            log.info("设备指令下发成功: clientId={}, commandId={}, commandType={}", 
                    clientId, command.getCommandId(), command.getCommandType());
            
        } catch (Exception e) {
            log.error("设备指令下发失败: clientId={}, commandId={}, error={}", 
                    clientId, command.getCommandId(), e.getMessage(), e);
            throw new BusinessException("设备指令下发失败: " + e.getMessage());
        }
    }

    /**
     * 更新设备在线状态
     */
    private void updateDeviceOnlineStatus(String clientId, boolean online) {
        String statusKey = "device:status:" + clientId;
        redisTemplate.opsForValue().set(statusKey, online ? "ONLINE" : "OFFLINE", 
                30, TimeUnit.MINUTES);
    }

    /**
     * 更新设备心跳时间
     */
    private void updateDeviceHeartbeat(String clientId) {
        String heartbeatKey = "device:heartbeat:" + clientId;
        redisTemplate.opsForValue().set(heartbeatKey, System.currentTimeMillis(), 
                5, TimeUnit.MINUTES);
    }

    /**
     * 发送设备上线事件
     */
    private void sendDeviceOnlineEvent(DeviceInfo deviceInfo) {
        DeviceOnlineEvent event = new DeviceOnlineEvent();
        event.setDeviceId(deviceInfo.getDeviceId());
        event.setDeviceType(deviceInfo.getDeviceType());
        event.setOnlineTime(LocalDateTime.now());
        
        kafkaTemplate.send("device.online", deviceInfo.getDeviceId(), 
                JSON.toJSONString(event));
    }

    /**
     * 发送设备离线事件
     */
    private void sendDeviceOfflineEvent(DeviceInfo deviceInfo) {
        DeviceOfflineEvent event = new DeviceOfflineEvent();
        event.setDeviceId(deviceInfo.getDeviceId());
        event.setDeviceType(deviceInfo.getDeviceType());
        event.setOfflineTime(LocalDateTime.now());
        
        kafkaTemplate.send("device.offline", deviceInfo.getDeviceId(), 
                JSON.toJSONString(event));
    }

    /**
     * 解析设备数据
     */
    private DeviceData parseDeviceData(String clientId, String topic, byte[] payload) {
        DeviceData deviceData = new DeviceData();
        deviceData.setClientId(clientId);
        deviceData.setTopic(topic);
        deviceData.setPayload(payload);
        deviceData.setReceiveTime(LocalDateTime.now());
        
        // 根据topic解析数据
        if (topic.contains("/data/")) {
            // 数据上报
            deviceData.setDataType("DATA_REPORT");
            deviceData.setDataContent(JSON.parseObject(new String(payload), Map.class));
        } else if (topic.contains("/status/")) {
            // 状态上报
            deviceData.setDataType("STATUS_REPORT");
            deviceData.setDataContent(JSON.parseObject(new String(payload), Map.class));
        } else if (topic.contains("/event/")) {
            // 事件上报
            deviceData.setDataType("EVENT_REPORT");
            deviceData.setDataContent(JSON.parseObject(new String(payload), Map.class));
        }
        
        return deviceData;
    }

    /**
     * 验证订阅权限
     */
    private boolean validateSubscribePermission(String clientId, String topic) {
        // 设备只能订阅自己的指令主题
        return topic.startsWith("/device/" + clientId + "/command/");
    }

    /**
     * 记录订阅关系
     */
    private void recordSubscription(String clientId, String topic) {
        String subscriptionKey = "device:subscription:" + clientId + ":" + topic;
        redisTemplate.opsForValue().set(subscriptionKey, "SUBSCRIBED", 
                24, TimeUnit.HOURS);
    }

    /**
     * 构建指令主题
     */
    private String buildCommandTopic(String clientId, String commandType) {
        return "/device/" + clientId + "/command/" + commandType;
    }

    /**
     * 构建MQTT发布消息
     */
    private MqttPublishMessage buildMqttPublishMessage(String topic, DeviceCommand command) {
        MqttFixedHeader fixedHeader = new MqttFixedHeader(
                MqttMessageType.PUBLISH, false, MqttQoS.AT_LEAST_ONCE, false, 0);
        
        MqttPublishVariableHeader variableHeader = new MqttPublishVariableHeader(
                topic, 0);
        
        byte[] payload = JSON.toJSONString(command).getBytes();
        
        return new MqttPublishMessage(fixedHeader, variableHeader, 
                Unpooled.wrappedBuffer(payload));
    }
}

2.2 Netty MQTT服务器启动

go 复制代码
/**
 * MQTT服务器启动类
 */
@Component
@Slf4j
public class MqttServer {

    @Autowired
    private MqttAccessGateway mqttAccessGateway;
    
    @Value("${mqtt.server.port:1883}")
    private int mqttPort;
    
    @Value("${mqtt.server.boss-threads:1}")
    private int bossThreads;
    
    @Value("${mqtt.server.worker-threads:4}")
    private int workerThreads;

    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel serverChannel;

    @PostConstruct
    public void start() throws InterruptedException {
        bossGroup = new NioEventLoopGroup(bossThreads);
        workerGroup = new NioEventLoopGroup(workerThreads);
        
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 1024)
                .option(ChannelOption.SO_REUSEADDR, true)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childHandler(new MqttChannelInitializer(mqttAccessGateway));
        
        ChannelFuture future = bootstrap.bind(mqttPort).sync();
        serverChannel = future.channel();
        
        log.info("MQTT服务器启动成功: port={}", mqttPort);
    }

    @PreDestroy
    public void stop() {
        if (serverChannel != null) {
            serverChannel.close();
        }
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
        
        log.info("MQTT服务器已关闭");
    }
}

/**
 * MQTT通道初始化器
 */
public class MqttChannelInitializer extends ChannelInitializer<SocketChannel> {

    private final MqttAccessGateway mqttAccessGateway;

    public MqttChannelInitializer(MqttAccessGateway mqttAccessGateway) {
        this.mqttAccessGateway = mqttAccessGateway;
    }

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        
        // MQTT编解码器
        pipeline.addLast(new MqttDecoder(1024 * 1024));
        pipeline.addLast(new MqttEncoder());
        
        // MQTT协议处理器
        pipeline.addLast(new MqttProtocolHandler(mqttAccessGateway));
        
        // 空闲检测
        pipeline.addLast(new IdleStateHandler(60, 0, 0, TimeUnit.SECONDS));
        pipeline.addLast(new MqttIdleHandler());
    }
}

3. 设备服务实现

3.1 设备认证服务

go 复制代码
/**
 * 设备认证服务
 * 负责设备注册、设备认证
 */
@Service
@Slf4j
public class DeviceAuthService {

    @Autowired
    private DeviceMapper deviceMapper;
    
    @Autowired
    private DeviceCredentialMapper deviceCredentialMapper;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 设备认证
     */
    public DeviceAuthResult authenticateDevice(String clientId, String username, String password) {
        try {
            // 1. 查询设备凭证
            DeviceCredential credential = deviceCredentialMapper.selectByClientId(clientId);
            if (credential == null) {
                return DeviceAuthResult.failed("设备不存在");
            }
            
            // 2. 验证用户名
            if (!credential.getUsername().equals(username)) {
                return DeviceAuthResult.failed("用户名错误");
            }
            
            // 3. 验证密码
            if (!validatePassword(password, credential.getPassword())) {
                return DeviceAuthResult.failed("密码错误");
            }
            
            // 4. 查询设备信息
            Device device = deviceMapper.selectById(credential.getDeviceId());
            if (device == null) {
                return DeviceAuthResult.failed("设备信息不存在");
            }
            
            // 5. 检查设备状态
            if (!"ACTIVE".equals(device.getStatus())) {
                return DeviceAuthResult.failed("设备未激活");
            }
            
            // 6. 构建设备信息
            DeviceInfo deviceInfo = convertToDeviceInfo(device);
            
            log.info("设备认证成功: clientId={}, deviceId={}", clientId, device.getDeviceId());
            
            return DeviceAuthResult.success(deviceInfo);
            
        } catch (Exception e) {
            log.error("设备认证失败: clientId={}, error={}", clientId, e.getMessage(), e);
            return DeviceAuthResult.failed("设备认证失败: " + e.getMessage());
        }
    }

    /**
     * 设备注册
     */
    @Transactional(rollbackFor = Exception.class)
    public DeviceRegisterResult registerDevice(DeviceRegisterRequest request) {
        try {
            // 1. 检查设备是否已存在
            Device existingDevice = deviceMapper.selectByDeviceNo(request.getDeviceNo());
            if (existingDevice != null) {
                return DeviceRegisterResult.failed("设备已存在");
            }
            
            // 2. 创建设备信息
            Device device = new Device();
            device.setDeviceNo(request.getDeviceNo());
            device.setDeviceName(request.getDeviceName());
            device.setDeviceType(request.getDeviceType());
            device.setManufacturer(request.getManufacturer());
            device.setModel(request.getModel());
            device.setStatus("INACTIVE");
            device.setCreateTime(LocalDateTime.now());
            device.setUpdateTime(LocalDateTime.now());
            
            deviceMapper.insert(device);
            
            // 3. 创建设备凭证
            String clientId = generateClientId(device.getId());
            String username = generateUsername(device.getId());
            String password = generatePassword();
            
            DeviceCredential credential = new DeviceCredential();
            credential.setDeviceId(device.getId());
            credential.setClientId(clientId);
            credential.setUsername(username);
            credential.setPassword(encryptPassword(password));
            credential.setCreateTime(LocalDateTime.now());
            credential.setUpdateTime(LocalDateTime.now());
            
            deviceCredentialMapper.insert(credential);
            
            log.info("设备注册成功: deviceId={}, deviceNo={}, clientId={}", 
                    device.getId(), device.getDeviceNo(), clientId);
            
            DeviceRegisterResult result = new DeviceRegisterResult();
            result.setSuccess(true);
            result.setDeviceId(device.getId());
            result.setClientId(clientId);
            result.setUsername(username);
            result.setPassword(password);
            result.setMessage("设备注册成功");
            
            return result;
            
        } catch (Exception e) {
            log.error("设备注册失败: deviceNo={}, error={}", 
                    request.getDeviceNo(), e.getMessage(), e);
            return DeviceRegisterResult.failed("设备注册失败: " + e.getMessage());
        }
    }

    /**
     * 验证密码
     */
    private boolean validatePassword(String inputPassword, String storedPassword) {
        // 使用BCrypt或其他加密算法验证密码
        return BCrypt.checkpw(inputPassword, storedPassword);
    }

    /**
     * 加密密码
     */
    private String encryptPassword(String password) {
        return BCrypt.hashpw(password, BCrypt.gensalt());
    }

    /**
     * 生成客户端ID
     */
    private String generateClientId(Long deviceId) {
        return "DEVICE_" + deviceId + "_" + System.currentTimeMillis();
    }

    /**
     * 生成用户名
     */
    private String generateUsername(Long deviceId) {
        return "USER_" + deviceId;
    }

    /**
     * 生成密码
     */
    private String generatePassword() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 转换为设备信息
     */
    private DeviceInfo convertToDeviceInfo(Device device) {
        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.setDeviceId(device.getId());
        deviceInfo.setDeviceNo(device.getDeviceNo());
        deviceInfo.setDeviceName(device.getDeviceName());
        deviceInfo.setDeviceType(device.getDeviceType());
        deviceInfo.setManufacturer(device.getManufacturer());
        deviceInfo.setModel(device.getModel());
        deviceInfo.setStatus(device.getStatus());
        return deviceInfo;
    }
}

3.2 设备连接管理器

go 复制代码
/**
 * 设备连接管理器
 * 负责设备连接状态管理、心跳检测
 */
@Service
@Slf4j
public class DeviceConnectionManager {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private DeviceMapper deviceMapper;
    
    private final ConcurrentHashMap<String, DeviceConnection> connections = new ConcurrentHashMap<>();

    /**
     * 注册设备连接
     */
    public DeviceConnection registerConnection(String clientId, Channel channel, DeviceInfo deviceInfo) {
        DeviceConnection connection = new DeviceConnection();
        connection.setClientId(clientId);
        connection.setDeviceId(deviceInfo.getDeviceId());
        connection.setChannel(channel);
        connection.setDeviceInfo(deviceInfo);
        connection.setConnectTime(LocalDateTime.now());
        connection.setLastHeartbeatTime(LocalDateTime.now());
        connection.setActive(true);
        
        connections.put(clientId, connection);
        
        // 缓存连接信息
        String connectionKey = "device:connection:" + clientId;
        redisTemplate.opsForValue().set(connectionKey, connection, 
                30, TimeUnit.MINUTES);
        
        log.info("设备连接注册成功: clientId={}, deviceId={}", 
                clientId, deviceInfo.getDeviceId());
        
        return connection;
    }

    /**
     * 移除设备连接
     */
    public void removeConnection(String clientId, Channel channel) {
        DeviceConnection connection = connections.remove(clientId);
        if (connection != null) {
            connection.setActive(false);
            connection.setDisconnectTime(LocalDateTime.now());
            
            // 删除缓存
            String connectionKey = "device:connection:" + clientId;
            redisTemplate.delete(connectionKey);
            
            log.info("设备连接移除成功: clientId={}", clientId);
        }
    }

    /**
     * 获取设备连接
     */
    public DeviceConnection getConnection(String clientId) {
        // 1. 从内存获取
        DeviceConnection connection = connections.get(clientId);
        if (connection != null && connection.isActive()) {
            return connection;
        }
        
        // 2. 从缓存获取
        String connectionKey = "device:connection:" + clientId;
        connection = (DeviceConnection) redisTemplate.opsForValue().get(connectionKey);
        
        return connection;
    }

    /**
     * 更新设备心跳
     */
    public void updateHeartbeat(String clientId) {
        DeviceConnection connection = connections.get(clientId);
        if (connection != null) {
            connection.setLastHeartbeatTime(LocalDateTime.now());
            
            // 更新缓存
            String connectionKey = "device:connection:" + clientId;
            redisTemplate.opsForValue().set(connectionKey, connection, 
                    30, TimeUnit.MINUTES);
        }
    }

    /**
     * 检查设备心跳超时
     */
    @Scheduled(fixedRate = 60000) // 每分钟检查一次
    public void checkHeartbeatTimeout() {
        try {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime timeoutThreshold = now.minusMinutes(5); // 5分钟超时
            
            List<String> timeoutClients = new ArrayList<>();
            
            for (Map.Entry<String, DeviceConnection> entry : connections.entrySet()) {
                String clientId = entry.getKey();
                DeviceConnection connection = entry.getValue();
                
                if (connection.getLastHeartbeatTime().isBefore(timeoutThreshold)) {
                    timeoutClients.add(clientId);
                }
            }
            
            // 处理超时设备
            for (String clientId : timeoutClients) {
                handleHeartbeatTimeout(clientId);
            }
            
            if (!timeoutClients.isEmpty()) {
                log.warn("检测到心跳超时设备: count={}, clients={}", 
                        timeoutClients.size(), timeoutClients);
            }
            
        } catch (Exception e) {
            log.error("检查设备心跳超时失败: error={}", e.getMessage(), e);
        }
    }

    /**
     * 处理心跳超时
     */
    private void handleHeartbeatTimeout(String clientId) {
        DeviceConnection connection = connections.get(clientId);
        if (connection != null) {
            // 关闭连接
            if (connection.getChannel() != null && connection.getChannel().isActive()) {
                connection.getChannel().close();
            }
            
            // 移除连接
            removeConnection(clientId, connection.getChannel());
            
            // 更新设备状态为离线
            updateDeviceOfflineStatus(connection.getDeviceId());
            
            log.warn("设备心跳超时,断开连接: clientId={}, deviceId={}", 
                    clientId, connection.getDeviceId());
        }
    }

    /**
     * 更新设备离线状态
     */
    private void updateDeviceOfflineStatus(Long deviceId) {
        Device device = deviceMapper.selectById(deviceId);
        if (device != null) {
            device.setStatus("OFFLINE");
            device.setUpdateTime(LocalDateTime.now());
            deviceMapper.updateById(device);
        }
    }
}

4. 设备指令服务实现

4.1 设备指令服务核心代码

go 复制代码
/**
 * 设备指令服务
 * 负责设备指令下发、指令状态跟踪
 */
@Service
@Slf4j
public class DeviceCommandService {

    @Autowired
    private DeviceCommandMapper deviceCommandMapper;
    
    @Autowired
    private MqttAccessGateway mqttAccessGateway;
    
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 下发设备指令
     */
    public DeviceCommandResult sendCommand(DeviceCommandRequest request) {
        try {
            // 1. 创建设备指令记录
            DeviceCommand command = createDeviceCommand(request);
            deviceCommandMapper.insert(command);
            
            // 2. 下发指令到设备
            mqttAccessGateway.sendDeviceCommand(request.getClientId(), command);
            
            // 3. 记录指令下发
            recordCommandSent(command);
            
            // 4. 构建返回结果
            DeviceCommandResult result = new DeviceCommandResult();
            result.setSuccess(true);
            result.setCommandId(command.getId());
            result.setCommandNo(command.getCommandNo());
            result.setStatus("SENT");
            result.setMessage("指令下发成功");
            
            log.info("设备指令下发成功: commandId={}, clientId={}, commandType={}", 
                    command.getId(), request.getClientId(), request.getCommandType());
            
            return result;
            
        } catch (Exception e) {
            log.error("设备指令下发失败: clientId={}, commandType={}, error={}", 
                    request.getClientId(), request.getCommandType(), e.getMessage(), e);
            return DeviceCommandResult.failed("指令下发失败: " + e.getMessage());
        }
    }

    /**
     * 处理设备指令响应
     */
    @KafkaListener(topics = "device.command.response", groupId = "device-command-group")
    public void handleCommandResponse(String message) {
        try {
            DeviceCommandResponse response = JSON.parseObject(message, DeviceCommandResponse.class);
            
            // 1. 查询指令记录
            DeviceCommand command = deviceCommandMapper.selectByCommandNo(
                    response.getCommandNo());
            if (command == null) {
                log.warn("设备指令记录不存在: commandNo={}", response.getCommandNo());
                return;
            }
            
            // 2. 更新指令状态
            command.setStatus(response.isSuccess() ? "SUCCESS" : "FAILED");
            command.setResponseTime(LocalDateTime.now());
            command.setResponseData(response.getResponseData());
            command.setErrorMessage(response.getErrorMessage());
            command.setUpdateTime(LocalDateTime.now());
            
            deviceCommandMapper.updateById(command);
            
            // 3. 发送指令响应事件
            sendCommandResponseEvent(command, response);
            
            log.info("设备指令响应处理成功: commandId={}, commandNo={}, status={}", 
                    command.getId(), command.getCommandNo(), command.getStatus());
            
        } catch (Exception e) {
            log.error("处理设备指令响应失败: error={}", e.getMessage(), e);
        }
    }

    /**
     * 创建设备指令
     */
    private DeviceCommand createDeviceCommand(DeviceCommandRequest request) {
        DeviceCommand command = new DeviceCommand();
        command.setCommandNo(generateCommandNo());
        command.setClientId(request.getClientId());
        command.setDeviceId(request.getDeviceId());
        command.setCommandType(request.getCommandType());
        command.setCommandData(request.getCommandData());
        command.setStatus("PENDING");
        command.setCreateTime(LocalDateTime.now());
        command.setUpdateTime(LocalDateTime.now());
        
        return command;
    }

    /**
     * 记录指令下发
     */
    private void recordCommandSent(DeviceCommand command) {
        String commandKey = "device:command:" + command.getCommandNo();
        redisTemplate.opsForValue().set(commandKey, command, 
                24, TimeUnit.HOURS);
    }

    /**
     * 发送指令响应事件
     */
    private void sendCommandResponseEvent(DeviceCommand command, DeviceCommandResponse response) {
        DeviceCommandResponseEvent event = new DeviceCommandResponseEvent();
        event.setCommandId(command.getId());
        event.setCommandNo(command.getCommandNo());
        event.setClientId(command.getClientId());
        event.setDeviceId(command.getDeviceId());
        event.setCommandType(command.getCommandType());
        event.setSuccess(response.isSuccess());
        event.setResponseData(response.getResponseData());
        event.setResponseTime(LocalDateTime.now());
        
        kafkaTemplate.send("device.command.response.event", 
                command.getCommandNo(), JSON.toJSONString(event));
    }

    /**
     * 生成指令编号
     */
    private String generateCommandNo() {
        return "CMD_" + System.currentTimeMillis() + "_" + 
                UUID.randomUUID().toString().substring(0, 8);
    }
}

5. 设备数据服务实现

5.1 设备数据服务核心代码

go 复制代码
/**
 * 设备数据服务
 * 负责设备数据接收、数据解析、数据转发
 */
@Service
@Slf4j
public class DeviceDataService {

    @Autowired
    private DeviceDataMapper deviceDataMapper;
    
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 处理设备数据
     */
    @Async("deviceDataExecutor")
    public void processDeviceData(DeviceData deviceData) {
        try {
            // 1. 保存设备数据
            saveDeviceData(deviceData);
            
            // 2. 根据数据类型处理
            switch (deviceData.getDataType()) {
                case "DATA_REPORT":
                    processDataReport(deviceData);
                    break;
                case "STATUS_REPORT":
                    processStatusReport(deviceData);
                    break;
                case "EVENT_REPORT":
                    processEventReport(deviceData);
                    break;
                default:
                    log.warn("未知的设备数据类型: dataType={}", deviceData.getDataType());
            }
            
            log.debug("设备数据处理成功: clientId={}, dataType={}", 
                    deviceData.getClientId(), deviceData.getDataType());
            
        } catch (Exception e) {
            log.error("处理设备数据失败: clientId={}, dataType={}, error={}", 
                    deviceData.getClientId(), deviceData.getDataType(), e.getMessage(), e);
        }
    }

    /**
     * 保存设备数据
     */
    private void saveDeviceData(DeviceData deviceData) {
        DeviceDataRecord record = new DeviceDataRecord();
        record.setClientId(deviceData.getClientId());
        record.setDeviceId(deviceData.getDeviceId());
        record.setDataType(deviceData.getDataType());
        record.setTopic(deviceData.getTopic());
        record.setDataContent(JSON.toJSONString(deviceData.getDataContent()));
        record.setReceiveTime(deviceData.getReceiveTime());
        record.setCreateTime(LocalDateTime.now());
        
        deviceDataMapper.insert(record);
    }

    /**
     * 处理数据上报
     */
    private void processDataReport(DeviceData deviceData) {
        // 1. 发送到数据上报主题
        DeviceDataReportEvent event = new DeviceDataReportEvent();
        event.setClientId(deviceData.getClientId());
        event.setDeviceId(deviceData.getDeviceId());
        event.setDataContent(deviceData.getDataContent());
        event.setReceiveTime(deviceData.getReceiveTime());
        
        kafkaTemplate.send("device.data.report", 
                deviceData.getClientId(), JSON.toJSONString(event));
        
        // 2. 更新设备数据缓存
        updateDeviceDataCache(deviceData);
    }

    /**
     * 处理状态上报
     */
    private void processStatusReport(DeviceData deviceData) {
        // 1. 发送到状态上报主题
        DeviceStatusReportEvent event = new DeviceStatusReportEvent();
        event.setClientId(deviceData.getClientId());
        event.setDeviceId(deviceData.getDeviceId());
        event.setStatusData(deviceData.getDataContent());
        event.setReportTime(deviceData.getReceiveTime());
        
        kafkaTemplate.send("device.status.report", 
                deviceData.getClientId(), JSON.toJSONString(event));
        
        // 2. 更新设备状态缓存
        updateDeviceStatusCache(deviceData);
    }

    /**
     * 处理事件上报
     */
    private void processEventReport(DeviceData deviceData) {
        // 发送到事件上报主题
        DeviceEventReportEvent event = new DeviceEventReportEvent();
        event.setClientId(deviceData.getClientId());
        event.setDeviceId(deviceData.getDeviceId());
        event.setEventData(deviceData.getDataContent());
        event.setEventTime(deviceData.getReceiveTime());
        
        kafkaTemplate.send("device.event.report", 
                deviceData.getClientId(), JSON.toJSONString(event));
    }

    /**
     * 更新设备数据缓存
     */
    private void updateDeviceDataCache(DeviceData deviceData) {
        String cacheKey = "device:data:latest:" + deviceData.getClientId();
        redisTemplate.opsForValue().set(cacheKey, deviceData.getDataContent(), 
                1, TimeUnit.HOURS);
    }

    /**
     * 更新设备状态缓存
     */
    private void updateDeviceStatusCache(DeviceData deviceData) {
        String cacheKey = "device:status:latest:" + deviceData.getClientId();
        redisTemplate.opsForValue().set(cacheKey, deviceData.getDataContent(), 
                30, TimeUnit.MINUTES);
    }
}

6. 数据模型定义

6.1 设备实体

go 复制代码
/**
 * 设备实体
 */
@Data
@TableName("t_device")
public class Device {
    
    /**
     * 设备ID
     */
    @TableId(type = IdType.AUTO)
    private Long id;
    
    /**
     * 设备编号
     */
    private String deviceNo;
    
    /**
     * 设备名称
     */
    private String deviceName;
    
    /**
     * 设备类型
     */
    private String deviceType;
    
    /**
     * 制造商
     */
    private String manufacturer;
    
    /**
     * 型号
     */
    private String model;
    
    /**
     * 设备状态:INACTIVE-未激活, ACTIVE-激活, OFFLINE-离线, ONLINE-在线
     */
    private String status;
    
    /**
     * 创建时间
     */
    private LocalDateTime createTime;
    
    /**
     * 更新时间
     */
    private LocalDateTime updateTime;
}

6.2 设备凭证实体

go 复制代码
/**
 * 设备凭证实体
 */
@Data
@TableName("t_device_credential")
public class DeviceCredential {
    
    /**
     * 凭证ID
     */
    @TableId(type = IdType.AUTO)
    private Long id;
    
    /**
     * 设备ID
     */
    private Long deviceId;
    
    /**
     * 客户端ID
     */
    private String clientId;
    
    /**
     * 用户名
     */
    private String username;
    
    /**
     * 密码(加密)
     */
    private String password;
    
    /**
     * 创建时间
     */
    private LocalDateTime createTime;
    
    /**
     * 更新时间
     */
    private LocalDateTime updateTime;
}

6.3 设备指令实体

go 复制代码
/**
 * 设备指令实体
 */
@Data
@TableName("t_device_command")
public class DeviceCommand {
    
    /**
     * 指令ID
     */
    @TableId(type = IdType.AUTO)
    private Long id;
    
    /**
     * 指令编号
     */
    private String commandNo;
    
    /**
     * 客户端ID
     */
    private String clientId;
    
    /**
     * 设备ID
     */
    private Long deviceId;
    
    /**
     * 指令类型
     */
    private String commandType;
    
    /**
     * 指令数据
     */
    private String commandData;
    
    /**
     * 指令状态:PENDING-待发送, SENT-已发送, SUCCESS-成功, FAILED-失败
     */
    private String status;
    
    /**
     * 响应时间
     */
    private LocalDateTime responseTime;
    
    /**
     * 响应数据
     */
    private String responseData;
    
    /**
     * 错误信息
     */
    private String errorMessage;
    
    /**
     * 创建时间
     */
    private LocalDateTime createTime;
    
    /**
     * 更新时间
     */
    private LocalDateTime updateTime;
}

6.4 设备数据记录实体

go 复制代码
/**
 * 设备数据记录实体
 */
@Data
@TableName("t_device_data")
public class DeviceDataRecord {
    
    /**
     * 记录ID
     */
    @TableId(type = IdType.AUTO)
    private Long id;
    
    /**
     * 客户端ID
     */
    private String clientId;
    
    /**
     * 设备ID
     */
    private Long deviceId;
    
    /**
     * 数据类型:DATA_REPORT-数据上报, STATUS_REPORT-状态上报, EVENT_REPORT-事件上报
     */
    private String dataType;
    
    /**
     * 主题
     */
    private String topic;
    
    /**
     * 数据内容(JSON)
     */
    private String dataContent;
    
    /**
     * 接收时间
     */
    private LocalDateTime receiveTime;
    
    /**
     * 创建时间
     */
    private LocalDateTime createTime;
}

7. 数据库设计

7.1 设备表

go 复制代码
CREATE TABLE `t_device` (
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '设备ID',
  `device_no` VARCHAR(64) NOT NULL COMMENT '设备编号',
  `device_name` VARCHAR(128) NOT NULL COMMENT '设备名称',
  `device_type` VARCHAR(32) NOT NULL COMMENT '设备类型',
  `manufacturer` VARCHAR(64) DEFAULT NULL COMMENT '制造商',
  `model` VARCHAR(64) DEFAULT NULL COMMENT '型号',
  `status` VARCHAR(32) NOT NULL COMMENT '设备状态:INACTIVE-未激活, ACTIVE-激活, OFFLINE-离线, ONLINE-在线',
  `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_device_no` (`device_no`),
  KEY `idx_device_type` (`device_type`),
  KEY `idx_status` (`status`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备表';

7.2 设备凭证表

go 复制代码
CREATE TABLE `t_device_credential` (
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '凭证ID',
  `device_id` BIGINT(20) NOT NULL COMMENT '设备ID',
  `client_id` VARCHAR(128) NOT NULL COMMENT '客户端ID',
  `username` VARCHAR(64) NOT NULL COMMENT '用户名',
  `password` VARCHAR(255) NOT NULL COMMENT '密码(加密)',
  `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_client_id` (`client_id`),
  UNIQUE KEY `uk_username` (`username`),
  KEY `idx_device_id` (`device_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备凭证表';

7.3 设备指令表

go 复制代码
CREATE TABLE `t_device_command` (
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '指令ID',
  `command_no` VARCHAR(64) NOT NULL COMMENT '指令编号',
  `client_id` VARCHAR(128) NOT NULL COMMENT '客户端ID',
  `device_id` BIGINT(20) NOT NULL COMMENT '设备ID',
  `command_type` VARCHAR(32) NOT NULL COMMENT '指令类型',
  `command_data` TEXT COMMENT '指令数据',
  `status` VARCHAR(32) NOT NULL COMMENT '指令状态:PENDING-待发送, SENT-已发送, SUCCESS-成功, FAILED-失败',
  `response_time` DATETIME DEFAULT NULL COMMENT '响应时间',
  `response_data` TEXT COMMENT '响应数据',
  `error_message` VARCHAR(512) DEFAULT NULL COMMENT '错误信息',
  `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_command_no` (`command_no`),
  KEY `idx_client_id` (`client_id`),
  KEY `idx_device_id` (`device_id`),
  KEY `idx_command_type` (`command_type`),
  KEY `idx_status` (`status`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备指令表';

7.4 设备数据表

go 复制代码
CREATE TABLE `t_device_data` (
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '记录ID',
  `client_id` VARCHAR(128) NOT NULL COMMENT '客户端ID',
  `device_id` BIGINT(20) NOT NULL COMMENT '设备ID',
  `data_type` VARCHAR(32) NOT NULL COMMENT '数据类型:DATA_REPORT-数据上报, STATUS_REPORT-状态上报, EVENT_REPORT-事件上报',
  `topic` VARCHAR(256) NOT NULL COMMENT '主题',
  `data_content` TEXT COMMENT '数据内容(JSON)',
  `receive_time` DATETIME NOT NULL COMMENT '接收时间',
  `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`),
  KEY `idx_client_id` (`client_id`),
  KEY `idx_device_id` (`device_id`),
  KEY `idx_data_type` (`data_type`),
  KEY `idx_receive_time` (`receive_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备数据表';

8. Mapper实现

8.1 设备Mapper

go 复制代码
/**
 * 设备Mapper
 */
@Mapper
public interface DeviceMapper extends BaseMapper<Device> {
    
    /**
     * 根据设备编号查询设备
     */
    @Select("SELECT * FROM t_device WHERE device_no = #{deviceNo}")
    Device selectByDeviceNo(@Param("deviceNo") String deviceNo);
    
    /**
     * 根据设备ID查询设备
     */
    @Select("SELECT * FROM t_device WHERE id = #{deviceId}")
    Device selectById(@Param("deviceId") Long deviceId);
}

8.2 设备凭证Mapper

go 复制代码
/**
 * 设备凭证Mapper
 */
@Mapper
public interface DeviceCredentialMapper extends BaseMapper<DeviceCredential> {
    
    /**
     * 根据客户端ID查询凭证
     */
    @Select("SELECT * FROM t_device_credential WHERE client_id = #{clientId}")
    DeviceCredential selectByClientId(@Param("clientId") String clientId);
    
    /**
     * 根据设备ID查询凭证
     */
    @Select("SELECT * FROM t_device_credential WHERE device_id = #{deviceId}")
    DeviceCredential selectByDeviceId(@Param("deviceId") Long deviceId);
}

8.3 设备指令Mapper

go 复制代码
/**
 * 设备指令Mapper
 */
@Mapper
public interface DeviceCommandMapper extends BaseMapper<DeviceCommand> {
    
    /**
     * 根据指令编号查询指令
     */
    @Select("SELECT * FROM t_device_command WHERE command_no = #{commandNo}")
    DeviceCommand selectByCommandNo(@Param("commandNo") String commandNo);
}

9. 配置类

9.1 MQTT配置

go 复制代码
# application.yml
mqtt:
  server:
    port: 1883
    boss-threads: 1
    worker-threads: 4
    max-message-size: 1048576
    keep-alive: 60

9.2 异步任务配置

go 复制代码
/**
 * 异步任务配置
 */
@Configuration
@EnableAsync
public class AsyncConfig {
    
    @Bean("deviceDataExecutor")
    public Executor deviceDataExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(50);
        executor.setQueueCapacity(1000);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("device-data-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

9.3 Kafka配置

go 复制代码
# application.yml
spring:
  kafka:
    bootstrap-servers: localhost:9092
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
      acks: all
      retries: 3
      batch-size: 16384
      linger-ms: 1
      buffer-memory: 33554432
    consumer:
      group-id: device-access-group
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      auto-offset-reset: latest
      enable-auto-commit: true

10. 性能优化策略

10.1 连接池优化

go 复制代码
/**
 * Netty连接池配置
 */
@Configuration
public class NettyConfig {
    
    @Bean
    public EventLoopGroup bossGroup() {
        return new NioEventLoopGroup(1);
    }
    
    @Bean
    public EventLoopGroup workerGroup() {
        return new NioEventLoopGroup(Runtime.getRuntime().availableProcessors() * 2);
    }
}

10.2 缓存优化

go 复制代码
/**
 * 设备连接缓存服务
 */
@Service
@Slf4j
public class DeviceConnectionCacheService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    /**
     * 缓存设备连接信息
     */
    public void cacheConnection(String clientId, DeviceConnection connection) {
        String cacheKey = "device:connection:" + clientId;
        redisTemplate.opsForValue().set(cacheKey, connection, 
                30, TimeUnit.MINUTES);
    }
    
    /**
     * 获取缓存的设备连接
     */
    public DeviceConnection getCachedConnection(String clientId) {
        String cacheKey = "device:connection:" + clientId;
        return (DeviceConnection) redisTemplate.opsForValue().get(cacheKey);
    }
}

10.3 批量处理优化

go 复制代码
/**
 * 设备数据批量处理服务
 */
@Service
@Slf4j
public class DeviceDataBatchService {
    
    @Autowired
    private DeviceDataMapper deviceDataMapper;
    
    private final List<DeviceDataRecord> batchBuffer = new ArrayList<>();
    private final int BATCH_SIZE = 100;
    
    /**
     * 批量保存设备数据
     */
    public synchronized void batchSave(DeviceDataRecord record) {
        batchBuffer.add(record);
        
        if (batchBuffer.size() >= BATCH_SIZE) {
            flushBatch();
        }
    }
    
    /**
     * 刷新批次
     */
    private void flushBatch() {
        if (batchBuffer.isEmpty()) {
            return;
        }
        
        try {
            // 批量插入
            deviceDataMapper.insertBatch(batchBuffer);
            batchBuffer.clear();
            
            log.debug("批量保存设备数据成功: count={}", BATCH_SIZE);
            
        } catch (Exception e) {
            log.error("批量保存设备数据失败: error={}", e.getMessage(), e);
        }
    }
    
    /**
     * 定时刷新批次
     */
    @Scheduled(fixedRate = 5000) // 每5秒刷新一次
    public void scheduledFlush() {
        flushBatch();
    }
}

11. 监控告警

11.1 业务指标监控

go 复制代码
/**
 * 业务指标监控
 */
@Component
@Slf4j
public class DeviceAccessMetricsMonitor {
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    /**
     * 记录设备连接
     */
    public void recordDeviceConnect(String deviceType) {
        Counter.builder("device.connect.total")
                .tag("device_type", deviceType)
                .register(meterRegistry)
                .increment();
    }
    
    /**
     * 记录设备断开
     */
    public void recordDeviceDisconnect(String deviceType) {
        Counter.builder("device.disconnect.total")
                .tag("device_type", deviceType)
                .register(meterRegistry)
                .increment();
    }
    
    /**
     * 记录设备数据上报
     */
    public void recordDeviceDataReport(String dataType) {
        Counter.builder("device.data.report.total")
                .tag("data_type", dataType)
                .register(meterRegistry)
                .increment();
    }
    
    /**
     * 记录设备指令下发
     */
    public void recordDeviceCommandSent(String commandType) {
        Counter.builder("device.command.sent.total")
                .tag("command_type", commandType)
                .register(meterRegistry)
                .increment();
    }
    
    /**
     * 记录设备心跳超时
     */
    public void recordHeartbeatTimeout() {
        Counter.builder("device.heartbeat.timeout.total")
                .register(meterRegistry)
                .increment();
    }
}

11.2 告警规则配置

go 复制代码
# prometheus-alert-rules.yml
groups:
  - name: device_access_alerts
    rules:
      - alert: DeviceConnectFailureRateHigh
        expr: rate(device_connect_total{status="failed"}[5m]) > 0.1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "设备连接失败率过高"
          description: "设备连接失败率超过10%,当前值: {{ $value }}"
      
      - alert: DeviceHeartbeatTimeoutHigh
        expr: rate(device_heartbeat_timeout_total[5m]) > 0.05
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "设备心跳超时率过高"
          description: "设备心跳超时率超过5%,当前值: {{ $value }}"
      
      - alert: DeviceCommandFailureRateHigh
        expr: rate(device_command_sent_total{status="failed"}[5m]) > 0.1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "设备指令下发失败率过高"
          description: "设备指令下发失败率超过10%,当前值: {{ $value }}"

12. 总结

本文深入讲解了设备服务接入系统的Java微服务后端架构实战,涵盖了以下核心内容:

  1. 系统架构设计:采用微服务架构,通过接入网关、设备服务、指令服务、数据服务协同完成设备接入管理

  2. MQTT协议支持:基于Netty实现MQTT协议服务器,支持设备连接、认证、消息发布订阅

  3. 设备注册认证:支持设备注册、设备凭证管理、设备认证

  4. 连接管理:实现设备连接状态管理、心跳检测、连接超时处理

  5. 指令下发:支持设备指令下发、指令状态跟踪、指令响应处理

  6. 数据上报:支持设备数据接收、数据解析、数据转发

  7. 性能优化:通过连接池、缓存、批量处理提升系统性能

  8. 监控告警:通过业务指标监控、告警规则保障系统稳定运行

通过本文的学习,读者可以掌握如何基于Java微服务架构实现一个高性能、高可用、可扩展的设备服务接入系统,为实际项目开发提供参考和指导。

相关推荐
Henry Zhu1231 天前
计算机硬件组成详解:从基础原理到现代架构(下)
架构
五岳1 天前
分库分表数据源ShardingSphereDataSource的Connection元数据误用问题分析
java·mysql·爬坑
带刺的坐椅1 天前
迈向 MCP 集群化:Solon AI (支持 Java8+)在解决 MCP 服务可扩展性上的探索与实践
java·ai·llm·solon·mcp
鼠爷ねずみ1 天前
SpringCloud前后端整体开发流程-以及技术总结文章实时更新中
java·数据库·后端·spring·spring cloud
代码or搬砖1 天前
String字符串
android·java·开发语言
leo__5201 天前
基于两步成像算法的聚束模式SAR MATLAB实现
开发语言·算法·matlab
Macbethad1 天前
自动化测试技术报告
开发语言·lua
不会画画的画师1 天前
Go开发指南:io/ioutil包应用和迁移指南
开发语言·后端·golang
2503_928411561 天前
12.22 wxml语法
开发语言·前端·javascript