news 2026/9/9 18:01:31

.NET开源实时监控系统:构建一站式可观测性仪表盘

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
.NET开源实时监控系统:构建一站式可观测性仪表盘

如果你手头管着几套 .NET 服务,尤其是微服务拆了一堆、部署在好几台机器上的那种,你大概率遇到过这种场景:某个接口突然变慢了,或者半夜收到告警说内存暴涨,你登录服务器一看,进程还在,但日志刷得像瀑布一样,根本来不及定位问题。这时候你会特别想要一个东西,能把这些服务的实时状态、请求指标、异常信息全部汇总到一个面板上,一眼看穿是哪个环节出了岔子。这就是我想聊的,一款 .NET 开源、功能强大的实时应用监控系统。

这个项目解决的是 .NET 应用可观测性(Observability)的问题。它不像 APM 商业方案那样重,也不像日志平台那样只关注日志,而是把健康检查、性能指标、请求追踪、异常捕获这几件事整合在一起,提供一个实时刷新的 Web 仪表盘。适合谁用?适合那些自己维护 .NET 服务、不想被商业监控工具绑定、又受够了“出了问题才上去翻日志”这种被动局面的开发者和运维同学。这篇博文,我会从技术选型、设计思路、部署实操到问题排查,把整个系统的搭建过程拆开讲清楚。

1. 监控系统的整体设计与技术选型思路

先说为什么需要这样一套东西,而不是直接上现成的 SkyWalking 或者 Prometheus + Grafana 组合。那套组合当然成熟,但是对于中小团队、尤其是 .NET 技术栈比较统一的团队来说,引入 Java 系的 SkyWalking 有额外运维成本,Prometheus 那套也需要单独维护指标采集和查询链路。而 .NET 生态里其实有很多现成的监控库,比如 App.Metrics、Prometheus.NET,但它们通常只是暴露指标端点,展示还要对接 Grafana。这不是说不好,而是对于“一把梭”的团队来说,链路拉得太长。

我当时看重这个开源项目,核心有几点。

第一,它足够轻。整个监控端可以用 NuGet 包引入,不需要部署独立的 Agent,也不依赖专门的数据库。它可以直接嵌入到 ASP.NET Core 中间件管道里,应用启动时自动收集请求数据、异常信息和运行时指标。

第二,它的实时性做得很好。不是传统的拉取模型,而是在应用内部做好数据聚合,通过 SignalR 推送到前端面板。这样你在浏览器上看到的请求量、错误率、响应时间,基本是秒级刷新的,不用手动刷新页面,也不用等 15 秒的 Prometheus 抓取周期。

第三,它把健康检查和监控面板打通了。很多时候健康检查是健康检查,监控是监控,两套东西分开配。这个项目里的健康检查结果是直接作为指标暴露在面板上的,哪个实例掉线、哪个依赖服务不可用,一眼就能看到。

技术选型上,如果要基于 .NET 生态去自研或者定制,我的建议是这样的顺序:采集层用DiagnosticSourceActivity,这是 .NET 官方的诊断机制,ASP.NET Core 的请求管道本身就往这里面写入事件,能拿到最原始的请求耗时、状态码、异常信息。存储层的话,如果是单机部署,直接用内存环形缓冲 + 定时落盘即可,数据量大了可以接 InfluxDB 或 TimescaleDB。实时推送层就是 SignalR,这一块 .NET 的 SignalR 生态很成熟,和前端配合也顺畅。仪表盘前端可以用 Vue 或者 Blazor。如果你希望整个项目保持纯 .NET,那 Blazor Server 模式是很自然的选择,因为 SignalR 连接本身就是它的通讯底座。

2. 核心功能拆解:这套监控系统到底能监控什么

一个功能强大的监控系统,绝对不是只显示一个“服务存活”状态,那是 2005 年的做法。真正的实时应用监控,至少要关注下面五个维度。

第一个维度是流量,也就是 QPS、每分钟请求数、活跃连接数这些。流量大小直接反映服务的繁忙程度,也能间接反映上下游调用是否正常。比如某个接口平时的流量是每分钟 500 次,突然降到了 10 次,那大概率是上游不调你了,或者你的服务已经异常到请求根本进不来。这些指标在系统里是会画曲线的,能看出趋势,而不是只看当前值。

第二个维度是响应时间,包括平均值、P50、P95、P99 这些分位数。只看平均值没有意义,因为平均响应时间会被少数慢请求拉高,但也会被大量快请求稀释。P95 和 P99 才是真正影响用户体验的区间。系统里有请求耗时分布直方图,一眼能看出是整体变慢,还是只有一部分请求异常。

第三个维度是错误率。这包括 4xx 和 5xx 状态码的比例、异常抛出的频次。特别是 .NET 里的未捕获异常,一旦在后台线程或者定时任务里抛出来,很容易被吞掉,传统日志未必能关联到具体的请求上下文。这个监控系统会把这些异常和请求路径关联起来,能直接看到是什么接口、什么参数、什么堆栈。

第四个维度是资源使用情况,包括内存、GC 暂停时间、线程池队列长度、CPU 时间。.NET 应用的内存问题很典型,比如内存泄漏、GC 频率过高,这些从任务管理器里看不出来,但是通过监控面板上的 GC 堆大小和 Gen0/Gen1/Gen2 回收次数,能快速判断是不是分配压力过大。

第五个维度是依赖健康状态。你的服务不可能光杆司令,总要调数据库、Redis、外部 HTTP API。监控系统会对这些依赖做健康检查的探针,并且记录每次调用的耗时和成功失败。这一步做得好的话,很多问题根本不需要看日志就能定位,比如数据库连接池耗尽、Redis 响应变慢,这些都是面板上直接数字体现出来的。

我当时把这套系统的展示层接到自己的项目后,最大的感受是:以前排查问题像翻旧账,得从日志里按时间线拼线索;现在面板上直接就是时间线,趋势变化、异常聚集点一目了然。这种从“事后查”到“实时看”的转变,才是“实时应用监控”真正的价值。

3. 安装部署与配置详解:从 NuGet 包到完整仪表盘

这部分我直接说实操路径。以仓库里比较流行的NetCoreMonitor方案为例,它本质上是一个 ASP.NET Core 中间件 + SignalR Hub + 内置前端面板的组合。你拿到项目的源码后,先按以下步骤部署。

第一步,准备环境。开发机上需要 .NET 8 SDK,如果是 Windows Server 或 Linux 服务器,需要安装对应版本的 ASP.NET Core Runtime,8.0 或 9.0 都能跑,但建议使用 LTS 版本。数据库方面,如果想要持久化历史数据,接 SQL Server 或者 PostgreSQL;如果只是看实时数据,默认的内存存储也够用。

第二步,发布项目。在项目根目录执行dotnet publish -c Release -o ./publish,发布完成后把 publish 目录拷贝到服务器上。注意,如果是 Linux 服务器,WebRoot 目录里的静态资源权限要设置正确,否则前端面板打不开。

第三步,配置。在appsettings.json里,核心配置有这几个 Kafka(注意:这里不是 Apache Kafka,而是监控系统的配置项名字,类似 appsettings 中定义的自定义节点):

{ "Monitor": { "AppName": "MyApi", "InstanceName": "instance-01", "Storage": "memory", "StorageConnectionString": "", "DataRetentionDays": 7, "EnableSignalR": true } }

AppName是服务的名字,在面板上会作为分组标识。InstanceName是实例名,如果你同一套服务部署了多个副本,在这里区分开。Storage支持内存和数据库两种,默认内存,重启会丢历史数据,所以要长期留存就配置数据库连接串。

第四步,在你的业务 API 项目里引入监控中间件。打开Program.cs,加上这几行:

var builder = WebApplication.CreateBuilder(args); // 注册监控服务 builder.Services.AddMonitor(builder.Configuration.GetSection("Monitor")); var app = builder.Build(); // 启用监控中间件,必须放在 UseRouting 之前或按官方文档位置 app.UseMonitor(); app.MapControllers(); app.Run();

这里有个细节需要注意,中间件注册的先后顺序很重要。监控中间件最好放在最早的位置之一,这样它能捕获整条管道内的请求事件。如果放在后面,比如放在静态文件中间件之后,静态资源这部分请求就监控不到了,虽然影响不大,但数据不完整。

第五步,启动服务和面板。启动业务 API,然后访问监控系统的独立面板站点。如果你用的是集成模式,面板就在同一个应用的/monitor路径下,登录后就能看到主界面。

面板上能看到四个核心区块:请求量趋势图、响应时间热力图、最近异常列表、依赖状态一览。请求量趋势图是按秒滚动的折线图,每条线对应一个实例,颜色不同。响应时间热力图则直观展示 P50、P95、P99 三条曲线的走势。这两块数据刷新频率可以配置,默认是 2 秒一次,已经足够灵敏。

部署过程中我踩过几个坑,这里直接标出来。

第一个坑是端口占用。监控面板默认会监听在 5000 端口,如果你业务 API 也碰巧用 5000,那就会冲突。建议在配置里显式设置"Url": "http://*:5200"给监控面板单独分配端口。

第二个坑是反向代理的 WebSocket 支持。SignalR 的实时推送依赖 WebSocket,如果你用 Nginx 做反向代理,一定要在 location 配置里加这些头:

proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";

不加的话,浏览器连接 WebSocket 会失败,画面永远转圈不出数据,但 HTTP 的请求指标又能看到一部分,这时候很容易误判成前端的问题。

第三个坑是权限控制。监控面板默认没有鉴权,知道端口就能访问。生产环境一定要在前面加一层认证,最简单的用 Nginx Basic Auth,或者如果系统支持集成认证,就挂上 OpenID Connect。不然别人看到你服务的实时请求数据,可能会暴露接口流量和异常信息,这属于信息泄露风险。

再补充一下数据持久化的配置方法。如果你选择 SQL Server 存储,表结构在项目的Database文件夹下能找到建表脚本,系统会自动建表。连接串的格式注意一点,需要给监控库单独建一个账号,不要用 sa 这种高权限账号连,安全习惯要好。

"Storage": "sqlserver", "StorageConnectionString": "Server=localhost;Database=MonitorDb;User Id=monitor_user;Password=your_password;TrustServerCertificate=True;"

数据库存储方式的性能,我实测过,在中等访问量的 API 上,每秒最多写入几十条指标数据,单表的插入压力完全扛得住。除非你每分钟请求量过万,否则不用考虑分表。数据保留天数建议根据磁盘空间来,默认 7 天是性价比比较高的配置。

4. 核心实现剖析:采集、聚合、推送这条链路是怎么设计的

既然标题强调了“功能强大”,光部署起来能用还不够,得知道这套系统内部是怎么把数据从业务代码里抽出来,跑到前端页面的。搞懂这条链路,不仅方便二次开发,遇到数据不准确或者延迟高的问题,也知道去哪个环节排查。

先看数据采集这一端。ASP.NET Core 的请求管道是基于中间件的,监控中间件就是利用这一点,把每个进来的 HttpContext 包裹起来,记录请求开始时间、请求路径、HTTP 方法、状态码、响应结束时间,然后计算耗时和成功失败。但是,如果只依赖中间件,你只能监控到通过 HTTP 进来的请求。像服务间调用、后台队列处理这些非 HTTP 场景,监控系统用的是DiagnosticSource

简单说,DiagnosticSource是 .NET 内部的一个事件总线,HttpClient、EF Core、ASP.NET Core 在关键节点都会发出诊断事件。监控系统里注册了对应的监听器,能拿到 HttpClient 的请求时长、数据库查询的耗时、连接池连接获取的等待时间。这样你不仅能看“接口慢”,还能知道是调用哪一个下游服务慢,或者是不是数据库查询本身就慢。

数据采集进来之后,不能直接往前端塞,因为流量稍微大一点,每秒几十上百条事件,全部推给浏览器,性能和带宽都撑不住。所以系统里做了一层聚合窗口。默认是 5 秒为一个窗口,在这 5 秒内对同一类型的指标做归并计算,比如统计总请求数、平均耗时、最大耗时、错误数。5 秒窗口结束,把聚合后的数据发送出去。

这个聚合策略很聪明,它大幅压缩了传输数据量。假设每秒请求量是 200,如果不聚合,5 秒就要传 1000 条原始记录;聚合之后,传的是一组指标数据,内容体量小得多,同时保留了对实时性的感知。这也是为什么面板上数据的粒度是 5 秒一个点,所以看到的趋势线比较平滑。

推送环节用的是 SignalR。SignalR 支持 WebSocket,也支持 Server-Sent Events 和长轮询的降级方案。监控系统里的 Hub,主要用来做服务端到浏览器端的指标推送。前端一连接,先发送一个快照,把过去 30 分钟的历史数据一次性拉下来,然后再实时订阅新的聚合数据流。

那么异常信息是怎么处理和展示的?这部分其实也很有意思。系统里有一个IExceptionCollector抽象接口,默认实现是捕获中间件管道内的异常,包括未捕获异常和记录到ILogger的异常。捕获到的异常会存储堆栈信息、请求路径、请求参数、用户标识(如果你在 HttpContext.Items 里放了),并在面板的异常列表里显示。每次异常出现时,面板右下角会弹一个实时通知,你能在问题发生后的几秒钟内就感知到,不用等日志采集系统转一圈。

除了请求链路和异常,还有很多系统级指标,比如进程的 CPU、内存、线程数、GC 信息。这些数据在 .NET 里可以用System.Diagnostics.ProcessGC.GetAllocatedBytesForCurrentThread这类 API 获取。监控系统内部有一个后台任务,每隔 10 秒采集一次系统指标,然后存到指标序列里。因为它采样频率低,对性能影响微乎其微。

整个链路里,最关键也最容易出性能瓶颈的地方是聚合计算。如果聚合逻辑设计得不好,在高并发下,锁竞争会导致请求变慢。这个项目里用的是 ConcurrentDictionary 按“窗口时间 + 请求路径 + 状态码”做键来聚合,每个键对应一个原子计数器,这样在多线程写入时不需要全局锁,能在保持吞吐量的同时保证数据准确。

如果你想在这个系统上扩展自定义指标,官方预留了接口,可以在业务代码里直接调用:

MonitorMetrics.IncrementCounter("order_created", tags: new { method = "api" }); MonitorMetrics.ObserveHistogram("payment_duration_ms", durationMs);

这样子,你在业务层面关心的一些特殊指标,比如订单创建量、支付耗时分布,也能直接反映到监控面板上。实际的部署项目里,我通常在业务核心路径上打三四这种点,监控的效果会更好。

5. 实践项目接入案例:用 30 分钟给一个 .NET 8 WebAPI 配上监控

讲了这么多原理和架构,我把一个具体的接入过程完整记录在这里。以我手上一个订单服务为例,它是 .NET 8 的单体 API,部署在内网两台服务器上,前面挂着一个 Nginx 做负载均衡。这个服务没有独立的可观测性基础设施,以前出问题全靠去服务器上翻日志。

整个接入分五步走。

第一步,确认版本和环境。服务本身是 .NET 8,SDK 版本 8.0.100 以上,目标框架net8.0。服务器是 CentOS 7.9,上面装了 .NET 8 Runtime。数据库用的 SQL Server 2019,监控库就建在上面。

第二步,NuGet 引用。在 API 项目里执行:

dotnet add package YourMonitorPackageName --version 2.1.0

这里用具体的包名替换实际项目的包名,因为截稿时的最新版本已经是 2.x,接口和 1.x 有一些差异。如果你是从网上找到的旧文章,要注意识别版本。

第三步,改Program.cs。代码改动很小,完整的改动如下:

using Monitor; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddMonitor(builder.Configuration.GetSection("Monitor")); var app = builder.Build(); app.UseMonitor(); app.MapControllers(); app.Run();

这里我用了一个独立配置节Monitor,对应的appsettings.json

{ "Monitor": { "AppName": "order-service", "InstanceName": "order-srv-01", "Storage": "sqlserver", "StorageConnectionString": "Server=10.10.10.15;Database=MonitorDb;User Id=monitor;Password=xxx;TrustServerCertificate=True;", "DataRetentionDays": 30, "EnableSignalR": true, "SignalRUrl": "http://localhost:5200/monitorHub" } }

第四步,在 Nginx 里把监控面板单独暴露成一个子域名或者独立端口。我的做法是监听 5200 端口,并配置好 WebSocket 升级头。完成后,重启 API 服务,访问监控面板地址,看到面板上的请求量曲线开始跳动,说明接入成功。

第五步,自定义埋点。我在订单创建、支付回调这两个核心方法里加了埋点,就是上一节提到的那两个方法调用。加了之后,面板上多出了两条自定义指标曲线,一个看订单创建的 QPS,一个看支付耗时的 P95。

这个接入做完之后,我们跑了一周,最大的发现:有一个敏感的接口,平时 P99 只有 200 毫秒,但每天下午两点到四点会出现一个持续的尖峰,P99 飙升到 2 秒以上。以前没人注意到这个问题,因为平均响应时间没有明显变化。看到面板上的异常趋势后,我定位到是这个时间段有个定时任务在批量拉取第三方数据,占用了大量数据库连接。后来把定时任务调整到凌晨执行,问题直接消失。这个案例算是“实时监控”价值的一个直观证明。

6. 常见问题排查与部署避坑指南

这个坑我觉得特别值得展开。很多人部署监控系统时,前面步骤都通了,面板能打开,但图表数据就是不刷新。遇到这种情况,第一件事打开浏览器开发者工具,看 Network 面板里有没有 WebSocket 连接,状态是不是101 Switching Protocols。如果不是,基本就是 Nginx 没配置升级头,或者前面挡了一层防火墙把 WebSocket 升级包拦掉了。

第二个常见问题是内存监控数据不准。你发现系统显示的内存占用和任务管理器看到的差很多。一般来说是采集原理不同。监控系统追踪的是托管堆的内存,任务管理器显示的是进程工作集,也就是物理内存。.NET 进程的物理内存包含 Native 内存和托管堆,两个数字天然不一样。如果你希望看到的是"接近 OOM 风险"的内存压力,用托管堆大小,也就是监控面板上的数值,更合理;如果你关心进程整体的占用,要看工作集。这两个概念别搞混。

第三个常见问题是高并发场景下,SignalR 推送延迟变大。这通常是因为聚合窗口里的计算堵塞了。建议把聚合窗口从 5 秒改成 10 秒,降低推送频率;同时检查前端页面是否开了很多标签页,每一个标签页都是一个独立连接,会占掉服务器端的线程资源。

第四个坑是数据库表增量太快导致磁盘爆掉。如果你的服务请求量很大,每条请求都产生指标记录,7 天的保留策略可能不够。可以缩短到 3 天,或者调整采样率。系统里有一个配置项叫SampleRate,默认是 100,意思是 100% 记录,你可以改成 10,即百分之十的采样。注意,采样会丢失细节,但能极大降低磁盘压力。

第五个坑比较隐蔽,就是监控中间件把自己的健康检查请求也记录进去了。负载均衡器每隔几秒访问一次/health端点,这部分请求会干扰指标统计。解决方法是配置路径过滤,把/health从采集列表里排除掉。

第六个问题是异常通知有时会重复弹出,同一时间同一接口异常,面板上出现好几条相同的记录。这是因为你同时在IExceptionCollector和你自己的全局异常过滤器里都捕获了异常,导致事件被记录了两次。解决办法是在自定义埋点时,先检查异常是否已经被处理过,或者调整监控系统的去重逻辑。

我整理了一张速查表,读者可以直接收藏:

现象可能原因处理方式
面板无数据,但页面能打开监控中间件未启用检查 Program.cs 是否调用 UseMonitor
数据有,但推送不更新反代未配置 WebSocket 升级头Nginx 加 Upgrade 和 Connection 头
内存数字与实际偏差大托管堆 vs 工作集概念混淆根据场景选对应指标解读
磁盘增长过快指标数据量过大缩短保留天数或降低采样率
异常重复记录多个异常处理器同时捕获统一异常处理入口,避免叠加
健康检查请求污染指标探针请求被记入业务统计配置路径过滤,排除 /health

这些坑都是实际部署中比较容易遇到的,写在这里希望能帮你少走点弯路。

7. 基于这套监控体系还能怎么扩展

说实话,监控系统的架子搭起来之后,思路一旦打开,能做的事情就多起来了。

第一个扩展方向是告警。系统目前侧重实时展示,但如果你希望它能在指标异常时主动通知你,可以在采集端加一个告警判断器。比如设置规则:5 分钟内错误率超过 5% 触发告警;或者 P95 响应时间超过 1000 毫秒持续 10 分钟触发告警。通知渠道建议先接钉钉、飞书或者企业微信的 Webhook,这种方式最快,不需要额外维护短信或者邮件服务。

第二个扩展方向是多实例聚合展示。如果你有多个服务实例,目前的面板以实例为维度展示,每个实例单独一条曲线。你可以做一层聚合,按AppName分组,把同一服务的所有实例指标汇总成整体趋势。尤其是做容量评估的时候,只看单实例是看不出整体压力的,聚合视图会很直观。

第三个扩展方向是接入日志查询。监控系统有异常列表,但异常只是日志中的一小类,完整的日志流查询还是需要专门的日志平台。不过你可以把日志系统和监控系统做联动:监控面板上发现某个实例异常时,点击进去跳转到日志平台,并带上报错的请求追踪 ID。这样,监控负责告诉你去哪儿看,日志负责让你看清事实。

第四个方向,也是最实用的,就是结合 traceId 做全链路追踪。.NET 的Activity本身就支持 W3C traceparent 标准,你可以在中间件里把 traceId 读取出来,存到日志上下文里。这样,监控系统里如果看到某个请求失败,你能拿着 traceId 去日志平台里找到这个请求经过的所有上下游调用记录,实现从“指标异常”到“根因日志”的闭环。

我自己的计划是下一阶段把告警规则做成可视化的配置页面,不通过改配置文件来修改规则,而是直接在 UI 上设置阈值、选择指标、配置通知渠道。这个功能在团队协作的时候特别有用,因为运维同事不一定愿意去改 JSON 文件。

这套系统还有很大的演进空间,就看你在实际使用场景里怎么去挖掘了。


我个人在实际部署中的体会是,不要指望监控系统能直接帮你把 Bug 改好,它的价值是让你在错误发生后的响应时间从“小时级”缩短到“分钟级”。错误本身难以避免,但早点看到、早点定位、早点止损,才是工程上的最优解。最后再分享一个小技巧:刚开始用的时候别急着配一堆告警规则,先让系统跑两周,把面板上的数据看熟了,知道自己的服务正常情况下长什么样,再针对性的加告警,你会发现规则准确率高很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 17:59:41

Ruffle Flash 播放器完整上手教程:3 种方式让老 SWF 文件跑起来

Ruffle Flash 播放器完整上手教程:3 种方式让老 SWF 文件跑起来 【免费下载链接】ruffle A Flash Player emulator written in Rust 项目地址: https://gitcode.com/GitHub_Trending/ru/ruffle Ruffle 是一个用 Rust 语言编写的 Adobe Flash Player 模拟器&a…

作者头像 李华
网站建设 2026/9/9 17:59:02

Babylon.js相机体系全解:从矩阵原理到工程实战

做3D开发这几年,我越来越觉得相机才是项目的门面。模型建得再精细,材质调得再通透,灯光布得再讲究,只要相机的位置、角度、视野没摆对,用户打开页面看到的就是一个穿模的视角、一片死黑,或者一个转两下就头…

作者头像 李华
网站建设 2026/9/9 17:59:02

macOS 安装 ESP-IDF 报错速查:依赖、环境与验证的最短路径

macOS 安装 ESP-IDF 报错速查:依赖、环境与验证的最短路径 【免费下载链接】esp-idf Espressif IoT Development Framework. Official development framework for Espressif SoCs. 项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf 在 macOS 上配置…

作者头像 李华
网站建设 2026/9/9 17:58:56

用 CodeWhisperer 写 Lambda 编排 ML 管道,上线首日数据漂移把我打回原形

用 CodeWhisperer 写 Lambda 编排 ML 管道,上线首日数据漂移把我打回原形 周五下午四点半,业务方在群里贴出一张截图:上周才上线的价格预测 API,对同一批商品连续两次调用给出的分数差了 12%。我翻看 CloudWatch 日志,发现特征分桶的分布从上午 10 点之后就开始悄悄偏移,而我的…

作者头像 李华
网站建设 2026/9/9 17:57:12

Create React App 如何添加 Flow 静态类型检查并配置 .flowconfig

Create React App 如何添加 Flow 静态类型检查并配置 .flowconfig 【免费下载链接】create-react-app Set up a modern web app by running one command. 项目地址: https://gitcode.com/gh_mirrors/cr/create-react-app Flow 是一个静态类型检查器,用于帮助…

作者头像 李华
网站建设 2026/9/9 17:56:50

PID控制原理与实战:从公式到调参,一篇讲透

简介:这是一份面向自动化、机器人及嵌入式开发者的PID算法学习资料包,涵盖理论、C代码实现和模拟演示三大模块,适合从入门到进阶的工程师对照实践。压缩包共66个文件,以C源码与头文件(.c/.h)、PDF/DOC文档、…

作者头像 李华