Java微服务可观测性实战:Prometheus+Grafana+SkyWalking全链路监控落地

随着Java微服务架构的普及,服务节点增多、调用链路复杂、跨服务依赖紧密等问题日益突出,传统监控仅能覆盖单一指标或节点,无法满足"可监控、可追踪、可告警、可分析"的全维度需求。可观测性作为微服务稳定性保障的核心能力,需通过指标监控、链路追踪、日志分析三大支柱构建闭环。本文结合企业级实战,拆解Prometheus+Grafana+SkyWalking的整合路径,从环境搭建、核心功能实现到问题排查优化,完整落地Java微服务全链路监控体系,适配生产环境高可用、高并发场景。

一、微服务可观测性痛点与技术选型逻辑

Java微服务在生产环境中常面临三大可观测性瓶颈:一是指标碎片化,各服务独立监控,无法关联分析CPU、内存、接口响应时间等跨维度指标;二是链路不可追溯,跨服务调用出现超时、异常时,难以定位问题出在哪个节点或环节;三是告警不精准,单一阈值告警易产生误报、漏报,无法结合业务场景联动分析。而Prometheus+Grafana+SkyWalking的组合,恰好能形成互补闭环,覆盖指标监控、可视化展示、全链路追踪核心需求。

1. 核心技术选型依据

针对Java微服务技术栈(Spring Cloud/Spring Boot),三者的选型适配性与核心价值如下:

Prometheus:作为开源时序数据库,核心优势在于高效的指标采集与存储,支持自定义指标、服务发现与灵活的查询语句(PromQL),能无缝对接Spring Boot Actuator暴露的监控端点,无需复杂适配即可采集JVM、接口、服务依赖等核心指标,且轻量化部署特性适配微服务分布式架构。

Grafana:专注于监控数据可视化,提供丰富的仪表盘模板与灵活的图表配置,可快速对接Prometheus数据源,将时序指标转化为直观的可视化图表,同时支持告警规则配置与多渠道通知(邮件、钉钉、企业微信),解决Prometheus原生可视化能力薄弱的问题。

SkyWalking:基于字节码增强技术的分布式链路追踪工具,无需侵入业务代码即可实现全链路调用追踪、服务依赖分析、接口性能统计,同时支持日志集成与告警,弥补Prometheus在链路追踪领域的短板,实现"指标+链路+日志"的一体化可观测。

补充说明:实际项目中需根据微服务规模选型------中小规模微服务可采用单机部署模式,大规模分布式场景需将Prometheus部署为集群模式(搭配Thanos实现数据分片与长期存储),SkyWalking采用集群部署保证链路数据不丢失,核心是确保监控数据采集延迟≤10s,链路追踪准确率100%。

2. 可观测性整体架构

本次落地的全链路监控体系采用分层架构,兼顾高内聚低耦合与可扩展性,同时适配Java微服务分布式特性,整体架构如下:

  • 数据采集层:通过Spring Boot Actuator暴露微服务指标,Prometheus通过Pull模式采集指标数据;SkyWalking Agent通过字节码增强采集服务调用链路、JVM信息与接口性能数据;日志数据通过Logback/Log4j集成SkyWalking MDC,携带链路ID输出至日志文件。

  • 数据存储层:Prometheus存储时序指标数据,支持本地存储与远程存储扩展;SkyWalking存储链路追踪数据、服务依赖关系与日志数据,底层可适配Elasticsearch、MySQL等存储介质(生产环境优先Elasticsearch保证查询性能)。

  • 可视化与分析层:Grafana负责指标数据可视化与告警配置,展示JVM状态、接口吞吐量、错误率等核心指标;SkyWalking UI负责链路追踪、服务拓扑图、日志关联分析,实现问题快速定位。

  • 告警与通知层:基于Prometheus与SkyWalking配置告警规则,当指标超出阈值或链路出现异常时,通过Grafana与SkyWalking联动发送告警通知,支持多渠道分发与告警分级处理。

二、核心功能实战落地

本节围绕"指标采集-链路追踪-可视化展示-告警配置"核心链路,结合Java微服务项目实战,拆解三大组件的整合配置与核心代码实现,所有操作均贴合Spring Boot/Spring Cloud规范,可直接复用至生产环境。

1. 环境搭建与依赖配置

基于Spring Boot 3.2.x、Spring Cloud Alibaba 2023.x构建微服务项目,核心依赖包括Spring Boot Actuator、Prometheus客户端、SkyWalking Agent,pom.xml关键配置如下:

xml 复制代码
<!-- Spring Boot 父依赖 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.5</version>
    <relativePath/>
</parent>

<!-- 核心依赖 -->
<dependencies>
    <!-- Spring Web 与微服务核心 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2023.0.1.0</version>
    </dependency>

    <!-- 指标采集依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>

    <!-- 日志与链路集成依赖 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.skywalking</groupId>
        <artifactId>apm-toolkit-logback-1.x</artifactId>
        <version>9.7.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.skywalking</groupId>
        <artifactId>apm-toolkit-trace</artifactId>
        <version>9.7.0</version>
    </dependency>

    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

配置文件application.yml中,初始化Actuator端点、Prometheus指标暴露、SkyWalking Agent配置,适配微服务注册与监控需求:

yaml 复制代码
spring:
  application:
    name: java-microservice-observability
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # 服务注册中心地址

# Actuator 配置:暴露所有监控端点
management:
  endpoints:
    web:
      exposure:
        include: '*' # 生产环境可按需精简,如health,prometheus,info
  endpoint:
    health:
      show-details: always # 展示健康检查详情
  metrics:
    tags:
      application: ${spring.application.name} # 为指标添加应用名称标签
    export:
      prometheus:
        enabled: true
    web:
      server:
        request:
          autotime:
            enabled: true # 自动统计接口请求时间

# SkyWalking 配置(Agent相关配置也可通过启动参数指定)
skywalking:
  agent:
    service-name: ${spring.application.name} # 服务名称(与微服务名称一致)
    collector-backend-service: 127.0.0.1:11800 # SkyWalking Collector地址
  logging:
    dir: logs/skywalking # Agent日志存储路径
    level: INFO

# 自定义日志配置(关联链路ID)
logging:
  level:
    root: INFO
    com.example: DEBUG
  file:
    name: logs/${spring.application.name}.log

2. 核心组件部署与配置

(1)Prometheus部署与指标采集配置

Prometheus采用Docker部署(也可单机部署),核心配置prometheus.yml如下,实现服务发现与指标采集规则定义:

yaml 复制代码
global:
  scrape_interval: 10s # 采集间隔,生产环境可根据需求调整
  evaluation_interval: 10s # 规则评估间隔

# 告警配置(后续关联Grafana)
alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']

# 规则文件配置(指标告警规则)
rule_files:
  - "rules/*.yml"

# 数据源配置
scrape_configs:
  # 采集Prometheus自身指标
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # 采集Java微服务指标(基于Nacos服务发现)
  - job_name: 'java-microservice'
    nacos_sd_configs: # 集成Nacos服务发现,自动发现微服务实例
      - server_addr: '127.0.0.1:8848'
        namespace: '' # 若使用Nacos命名空间,需指定
        group: 'DEFAULT_GROUP'
        service_name: '' # 为空则发现所有服务,也可指定具体服务名称
        refresh_interval: 30s # 服务发现刷新间隔
    metrics_path: '/actuator/prometheus' # 微服务暴露的Prometheus指标端点
    relabel_configs:
      - source_labels: [__meta_nacos_service_name]
        regex: '(.*)'
        target_label: 'service'
        replacement: '$1'
      - source_labels: [__meta_nacos_ip]
        regex: '(.*)'
        target_label: 'ip'
        replacement: '$1'

启动Prometheus容器命令:

bash 复制代码
docker run -d \
  --name prometheus \
  -p 9090:9090 \
  -v /path/to/prometheus.yml:/etc/prometheus/prometheus.yml \
  -v /path/to/rules:/etc/prometheus/rules \
  prom/prometheus:v2.45.0 \
  --config.file=/etc/prometheus/prometheus.yml

验证:访问http://localhost:9090,在Graph页面输入PromQL查询语句(如http_server_requests_seconds_count),可查看微服务接口请求计数指标,确认采集正常。

(2)Grafana部署与仪表盘配置

Grafana同样采用Docker部署,启动命令如下:

bash 复制代码
docker run -d \
  --name grafana \
  -p 3000:3000 \
  -v grafana-storage:/var/lib/grafana \
  grafana/grafana:10.2.0

初始化配置:

  1. 访问http://localhost:3000,使用默认账号admin/admin登录,首次登录需修改密码;

  2. 添加数据源:选择Prometheus,配置数据源地址为http://prometheus:9090(容器内网络)或http://宿主机IP:9090(宿主机网络),保存并测试连接;

  3. 导入仪表盘:推荐导入官方Java微服务仪表盘模板(ID:4701,适配Spring Boot Actuator指标),或自定义仪表盘,展示JVM内存、GC次数、接口吞吐量、错误率、响应时间等核心指标。

自定义仪表盘核心指标:通过PromQL配置关键图表,例如:

  • 接口总吞吐量:sum(rate(http_server_requests_seconds_count[5m])) by (application, endpoint);

  • 接口平均响应时间:sum(rate(http_server_requests_seconds_sum[5m])) / sum(rate(http_server_requests_seconds_count[5m])) by (application, endpoint);

  • JVM堆内存使用量:jvm_memory_used_bytes{area="heap", application="KaTeX parse error: Expected 'EOF', got '}' at position 13: application"}̲ / jvm_memory_m...application"} * 100。

(3)SkyWalking部署与链路追踪配置

SkyWalking采用"Collector+UI+Storage"架构,生产环境推荐使用Elasticsearch作为存储介质,Docker Compose部署配置如下(docker-compose.yml):

yaml 复制代码
version: '3'
services:
  elasticsearch:
    image: elasticsearch:8.6.0
    container_name: elasticsearch
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms2g -Xmx2g
      - xpack.security.enabled=false
    volumes:
      - es-data:/usr/share/elasticsearch/data
    networks:
      - skywalking-network

  skywalking-oap-server:
    image: apache/skywalking-oap-server:9.7.0
    container_name: skywalking-oap
    ports:
      - "11800:11800" # Agent数据接收端口
      - "12800:12800" # UI访问端口
    environment:
      - SW_STORAGE=elasticsearch
      - SW_STORAGE_ES_CLUSTER_NODES=elasticsearch:9200
      - SW_HEALTH_CHECKER=default
      - JAVA_OPTS=-Xms2g -Xmx2g
    depends_on:
      - elasticsearch
    networks:
      - skywalking-network

  skywalking-ui:
    image: apache/skywalking-ui:9.7.0
    container_name: skywalking-ui
    ports:
      - "8080:8080"
    environment:
      - SW_OAP_ADDRESS=http://skywalking-oap:12800
    depends_on:
      - skywalking-oap-server
    networks:
      - skywalking-network

networks:
  skywalking-network:
    driver: bridge

volumes:
  es-data:

启动命令:docker-compose up -d,验证:访问http://localhost:8080,可看到SkyWalking UI界面,显示已接入的微服务实例与链路数据。

微服务启动配置:在微服务启动脚本中指定SkyWalking Agent,实现链路数据采集:

bash 复制代码
java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar \
     -jar your-microservice.jar \
     --spring.profiles.active=prod

3. 链路追踪与日志关联实战

(1)全链路追踪实现

SkyWalking通过字节码增强技术,自动采集微服务间调用链路,无需侵入业务代码。对于需要手动标记关键链路的场景(如异步方法、自定义埋点),可使用SkyWalking Toolkit API:

java 复制代码
import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.apache.skywalking.apm.toolkit.trace.Trace;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@RequestMapping("/api/order")
public class OrderController {

    @Resource
    private RestTemplate restTemplate;
    @Resource
    private OrderService orderService;

    // 标记为追踪链路入口
    @Trace
    @GetMapping("/create")
    public String createOrder(Long userId, Long productId) {
        // 手动添加链路标签,便于排查
        ActiveSpan.tag("userId", userId.toString());
        ActiveSpan.tag("productId", productId.toString());
        
        // 调用商品服务接口(跨服务链路自动追踪)
        String productInfo = restTemplate.getForObject(
                "http://java-microservice-product/api/product/get/" + productId,
                String.class
        );
        
        // 调用本地服务方法(自动追踪)
        orderService.saveOrder(userId, productId);
        
        return "订单创建成功,商品信息:" + productInfo;
    }
}

// 本地服务类
@Service
public class OrderService {
    // 标记为追踪方法
    @Trace
    public void saveOrder(Long userId, Long productId) {
        // 业务逻辑:保存订单到数据库
        ActiveSpan.info("订单保存成功,userId: " + userId + ", productId: " + productId);
    }
}

验证:访问接口后,在SkyWalking UI的"追踪"页面,可查看完整链路调用流程,包括各环节耗时、请求参数、返回结果,若出现异常,会标记异常节点与堆栈信息,快速定位问题。

(2)日志与链路关联

通过Logback配置,将SkyWalking链路ID(traceId)融入日志,实现日志与链路的关联查询,便于通过日志定位链路问题。修改logback-spring.xml配置:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 引入SkyWalking日志转换器 -->
    <conversionRule conversionWord="traceId" converterClass="org.apache.skywalking.apm.toolkit.logback.v1.x.LogbackPatternConverter"/>

    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 日志格式:包含traceId、时间、级别、类名、日志内容 -->
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%traceId] %-5level %logger{50} - %msg%n
        </encoder>
    </appender>

    <!-- 文件输出 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
${LOG_FILE}<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%traceId] %-5level %logger{50} - %msg%n
        </encoder>
    </appender>

    <!-- 日志级别与输出源 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

日志输出效果:包含traceId,可通过SkyWalking UI根据traceId查询对应链路,或通过日志工具(如ELK)根据traceId筛选关联日志:

4. 告警规则配置与问题排查

(1)Prometheus+Grafana告警配置

在Prometheus规则文件中定义告警规则(如rules/alert-rules.yml),针对接口错误率、JVM内存使用率、服务不可用等场景配置阈值:

yaml 复制代码
groups:
  - name: java-microservice-alert
    rules:
      # 接口错误率告警:5分钟内错误率超过5%
      - alert: 接口错误率过高
        expr: sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) by (application) / sum(rate(http_server_requests_seconds_count[5m])) by (application) > 0.05
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: "服务{{ $labels.application }}接口错误率过高"
          description: "服务{{ $labels.application }}过去5分钟接口错误率为{{ $value | multiply 100 | printf \"%.2f\" }}%,超过阈值5%"

      # JVM堆内存使用率告警:超过85%
      - alert: JVM堆内存使用率过高
        expr: jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} > 0.85
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "服务{{ $labels.application }}JVM堆内存使用率过高"
          description: "服务{{ $labels.application }}JVM堆内存使用率为{{ $value | multiply 100 | printf \"%.2f\" }}%,超过阈值85%"

      # 服务不可用告警:实例数为0
      - alert: 服务不可用
        expr: count(up{job="java-microservice"}) by (application) == 0
        for: 30s
        labels:
          severity: critical
        annotations:
          summary: "服务{{ $labels.application }}不可用"
          description: "服务{{ $labels.application }}当前无可用实例,可能已宕机"

在Grafana中配置告警通知渠道(如钉钉),当告警触发时,自动发送通知至指定群组,包含告警详情与排查建议。

(2)典型问题排查实战
  1. 接口超时问题:通过SkyWalking UI定位链路中耗时最长的节点,若为跨服务调用超时,检查被调用服务响应时间与网络状态;若为本地方法耗时过长,结合日志与JVM监控(如GC次数、线程状态)排查是否存在内存泄漏、锁竞争等问题。

  2. 服务不可用告警:首先在Prometheus中查询up指标,确认服务实例是否正常;若实例正常但采集失败,检查Actuator端点是否正常暴露、网络是否通畅;若实例异常,查看微服务日志与SkyWalking Agent日志,定位启动失败原因。

  3. JVM内存溢出预警:通过Grafana查看JVM堆内存变化趋势,若内存持续上涨且GC后无法释放,结合内存快照(jmap)与SkyWalking链路,排查是否存在大对象未释放、缓存滥用等问题。

三、工业级优化:从原型到生产环境

上述实现为基础原型,生产环境中需针对高并发、大数据量、高可用场景做进一步优化,确保监控体系稳定可靠。

1. 性能优化:降低监控开销

① 指标采集优化:精简Actuator暴露的端点,避免采集无用指标;调整Prometheus采集间隔,非核心指标可延长至30s-1min,减少服务与网络开销;② SkyWalking优化:调整Agent采样率(默认100%,高并发场景可降至50%-80%),避免链路数据过多占用存储与网络资源;采用异步日志输出,减少日志打印对业务接口的影响;③ 存储优化:Prometheus采用远程存储(如Thanos)实现数据分片与长期存储,SkyWalking搭配Elasticsearch集群,提升链路与日志查询性能。

2. 高可用设计:避免监控单点故障

① Prometheus集群部署:采用主从架构+服务发现,避免单点故障;通过Thanos实现指标数据全局聚合与高可用存储;② SkyWalking集群部署:Collector采用集群模式,UI与Storage独立部署,确保链路数据不丢失;③ 告警冗余:配置多渠道告警通知(钉钉+邮件+短信),重要告警分级处理,避免告警遗漏;④ 网络隔离:监控组件与业务服务部署在同一内网,确保数据传输安全与稳定,避免外网波动影响。

3. 功能增强:适配复杂业务场景

① 日志集中化:集成ELK/EFK栈,实现日志集中收集、检索与分析,结合SkyWalking traceId实现日志与链路的全关联;② 自定义指标:针对业务场景开发自定义指标(如订单转化率、支付成功率),通过Micrometer注册至Prometheus,实现业务指标与技术指标一体化监控;③ 链路分析:基于SkyWalking链路数据,构建服务依赖拓扑图与性能基线,自动识别链路异常波动;④ 多环境适配:通过Nacos配置中心,实现开发、测试、生产环境监控配置隔离,避免环境混淆。

4. 安全加固:保障监控数据安全

① 权限管控:Grafana与SkyWalking UI配置角色权限,不同人员分配不同操作权限(如开发人员仅可查看,运维人员可配置告警);② 数据加密:监控数据传输采用HTTPS加密,避免数据泄露;③ 日志脱敏:对日志中的敏感信息(如手机号、身份证号)进行脱敏处理,符合数据安全规范;④ 审计日志:记录监控组件的操作日志(如告警配置修改、权限变更),支持审计追溯。

四、常见问题与踩坑总结

1. SkyWalking链路追踪丢失

现象:微服务调用链路不完整,部分节点未被追踪。解决方案:检查Agent配置的service-name与微服务名称一致;确保跨服务调用使用的客户端(RestTemplate、Feign)被SkyWalking Agent拦截(需适配对应版本);排查是否存在异步方法未手动标记@Trace注解的情况。

2. Prometheus指标采集失败

现象:Grafana中无微服务指标数据,Prometheus Targets页面显示实例不可达。解决方案:检查微服务Actuator端点是否正常访问(http://ip:port/actuator/prometheus);确认Prometheus服务发现配置正确,Nacos服务注册正常;排查网络防火墙是否开放对应端口(如9090、8848)。

3. Grafana告警误报/漏报

现象:告警规则触发异常,或指标超出阈值未告警。解决方案:优化告警规则的for参数,避免瞬时波动导致误报;调整PromQL语句,确保指标计算准确;检查Grafana数据源连接状态,确保告警规则能正常读取指标数据。

4. SkyWalking Agent启动失败

现象:微服务启动时Agent加载失败,报错"Agent core start failed"。解决方案:检查Agent版本与微服务JDK版本适配(如JDK17需使用SkyWalking 9.5+版本);确认Collector地址正确且网络通畅;调整JVM堆内存,避免Agent加载时内存不足。

五、总结与展望

本文基于Prometheus+Grafana+SkyWalking,实现了Java微服务全链路可观测性体系,通过指标监控、链路追踪、日志关联的一体化整合,解决了微服务架构下的问题定位难、监控碎片化、告警不精准等核心痛点。相较于单一监控工具,该组合覆盖全维度可观测需求,且能无缝适配Java微服务生态,稳定性与扩展性更强,适合生产环境部署。

未来可进一步探索的方向:① 智能化监控:融合AI算法,实现指标异常预测、链路故障根因自动分析,减少人工排查成本;② 分布式追踪与日志深度融合:通过traceId串联全链路日志、指标与链路数据,实现"一键定位"故障;③ 多云/混合云适配:适配K8s容器化环境,实现微服务容器化部署后的可观测性全覆盖;④ 业务可观测性:将可观测性从技术层面延伸至业务层面,通过业务指标监控,提前感知业务异常。

对于Java微服务开发者与运维人员而言,一套完善的可观测性体系不仅是稳定性保障的"护身符",更是业务优化与技术迭代的"指南针",助力企业在微服务架构下实现高效运维与业务

相关推荐
Java程序员威哥1 小时前
【包教包会】SpringBoot依赖Jar指定位置打包:配置+原理+避坑全解析
java·开发语言·spring boot·后端·python·微服务·jar
小饼干超人1 小时前
如何兼容不同版本的 scikit-learn(sklearn)库,统一获取“均方根误差(RMSE)”的计算函数
python·scikit-learn·sklearn
a程序小傲2 小时前
中国邮政Java面试被问:边缘计算的数据同步和计算卸载
java·服务器·开发语言·算法·面试·职场和发展·边缘计算
全栈软件开发2 小时前
PHP实时消息聊天室源码 PHP+WebSocket
开发语言·websocket·php
毕设源码-邱学长2 小时前
【开题答辩全过程】以 面向警务应用的问答系统的设计与实现为例,包含答辩的问题和答案
java
UR的出不克2 小时前
基于PyTorch的MNIST手写数字识别系统 - 从零到实战
人工智能·python·数字识别
小尧嵌入式2 小时前
【Linux开发二】数字反转|除数累加|差分数组|vector插入和访问|小数四舍五入及向上取整|矩阵逆置|基础文件IO|深入文件IO
linux·服务器·开发语言·c++·线性代数·算法·矩阵
one____dream2 小时前
【算法】大整数数组连续进位
python·算法
one____dream2 小时前
【算法】合并两个有序链表
数据结构·python·算法·链表