Files
Meshray-Manager/docs/gRPC 架构最终修复方案.md
2026-06-30 15:14:37 +08:00

490 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MeshRay gRPC 架构真相与最终修复方案
**发现时间**: 2026-03-24
**状态**: 🔴 **确认问题存在** - 需要修复
**关键发现**: Ctr 只有 Core 客户端,没有 gRPC 服务器
---
## 🚨 最终确认:gRPC 服务器确实未启动
### **代码证据**
```go
// internal/ctr/ctr.go:33-46
func NewCtr(name string, networkID uint64, config *CtrConfig, logger *zap.Logger) (*Ctr, error) {
ctr := &Ctr{
name: name,
networkID: networkID,
config: config,
logger: logger,
coreClients: make(map[string]*CoreClient), // ← 只有客户端
}
// 初始化 WireGuard 管理器
ctr.wgManager = NewWGManager(logger)
return ctr, nil // ← 没有创建 gRPC 服务器
}
```
**搜索结果**:
```bash
grep -r "grpc.NewServer" internal/ctr/ # ❌ 无结果
grep -r "RegisterCoreService" internal/ctr/ # ❌ 无结果
grep -r "Serve(lis)" internal/ctr/ # ❌ 无结果
```
**结论**:
-**gRPC 服务器确实未启动** - 审查报告正确
-`core/grpc_service.go` 的实现无处可用
-`core/client/core_client.go` 会连接失败
---
## 🏗️ 架构分析:谁应该在 gRPC 两端?
### **当前架构(错误的)**
```
┌─────────────┐
│ Core │ ← gRPC 服务端(core/grpc_service.go
│ (库) │ 但没有人启动它!
└─────────────┘
│ gRPC 调用(127.0.0.1:50051
┌─────────────┐
│ Ctr │ ← gRPC 客户端(core/client/core_client.go
│ (调度中心) │ 尝试连接但会失败
└─────────────┘
```
### **正确的架构**
```
┌─────────────────────────────────┐
│ APIServer │
│ (internal/api/server.go) │
│ │
│ ┌───────────┐ ┌────────────┐ │
│ │ Ctr │ │ GRPCServer │ │
│ │(调度中心) │ │ (服务端) │ │
│ │ │ │ │ │
│ │ ┌───────┐ │ │ ┌────────┐ │ │
│ │ │Core │ │ │ │Core │ │ │
│ │ │Client │ │ │ │Service │ │ │
│ │ │(客户端)│ │ │ │(服务端)│ │ │
│ │ └───────┘ │ │ └────────┘ │ │
│ └───────────┘ └────────────┘ │
└─────────────────────────────────┘
↑ ↑
│ │
└──────┬─────────┘
127.0.0.1:50051
┌─────────────┐
│ Core │ ← 作为独立进程运行
│ (可选项) │ 或通过库集成
└─────────────┘
```
**关键点**:
1. ✅ Ctr 和 gRPC Server 都在 APIServer 内部
2. ✅ Ctr 的 Core Client 连接到 gRPC Server
3. ✅ gRPC Server 使用 `core/grpc_service.go` 的实现
4. ✅ Core 可以作为库(集成到进程内)或独立进程
---
## 💡 两种可行的架构方案
### **方案 A: 进程内集成(推荐)**
**特点**: Core 作为库集成到 meshray 进程中
```go
// internal/api/server.go
type APIServer struct {
engine *gin.Engine
config *config.Config
logger *zap.Logger
// Ctr 层
ctrClient *ctr.Ctr
// gRPC 服务器
grpcServer *grpc.Server
coreInst *core.Core // Core 实例(库)
}
func (s *APIServer) Start() error {
// 1. 创建 Core 实例(作为库)
s.coreInst = core.NewCore(s.logger)
// 2. 创建 gRPC 服务器
lis, err := net.Listen("tcp", ":50051")
if err != nil {
panic(fmt.Sprintf("无法监听 50051 端口:%v", err))
}
s.grpcServer = grpc.NewServer()
// 3. 注册 Core 服务(使用 core/grpc_service.go
coreService := core.NewCoreServiceServer(s.coreInst, s.logger)
core.RegisterCoreService(s.grpcServer, coreService)
// 4. 启动 gRPC 服务器
go func() {
s.logger.Info("启动 gRPC 服务器", zap.Int("port", 50051))
if err := s.grpcServer.Serve(lis); err != nil {
s.logger.Error("gRPC 服务器错误", zap.Error(err))
}
}()
// 5. 创建 Ctr(会自动连接 127.0.0.1:50051
s.ctrClient, err = ctr.NewCtr("default", 1, &ctr.CtrConfig{GRPCPort: 50051}, s.logger)
if err != nil {
panic(fmt.Sprintf("初始化 ctr 失败:%v", err))
}
// 6. 启动 HTTP 服务器
return s.engine.Run(":8080")
}
```
**优点**:
- ✅ 简单直接,无需额外进程
- ✅ 部署方便(单个二进制文件)
- ✅ 通信高效(进程内调用)
**缺点**:
- ❌ Core 和 API 耦合在同一进程
---
### **方案 B: 独立 Core 进程(微服务)**
**特点**: Core 作为独立进程运行
```bash
# 启动 Core 服务
./meshray-core --grpc-port=50051 &
# 启动 API 服务器
./meshray-api serve
```
**优点**:
- ✅ 完全解耦
- ✅ 可以独立扩展
- ✅ 符合微服务架构
**缺点**:
- ❌ 部署复杂(需要管理两个进程)
- ❌ 需要额外的进程监控
---
## 🎯 推荐方案:进程内集成(方案 A)
### **理由**
1. ✅ 符合当前项目结构(Core 在 `core/` 目录作为库)
2. ✅ 部署简单(用户只需运行一个命令)
3. ✅ 性能更好(无网络开销)
4. ✅ 调试方便(单进程日志)
---
## 📝 详细修复步骤
### **步骤 1: 修改 internal/api/server.go**
```go
package api
import (
"context"
"fmt"
"net"
"time"
"git.zkcoi.com/zkcoi/meshray/core"
"git.zkcoi.com/zkcoi/meshray/internal/ctr"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"google.golang.org/grpc"
)
type APIServer struct {
engine *gin.Engine
config *config.Config
logger *zap.Logger
store *store.Store
// Ctr 层
ctrClient *ctr.Ctr
// gRPC 服务器
grpcServer *grpc.Server
coreInst *core.Core
}
func NewAPIServer(cfg *config.Config) (*APIServer, error) {
// ... 现有代码 ...
return &APIServer{
engine: engine,
config: cfg,
logger: logger,
store: store,
// ctrClient 和 grpcServer 在 Start 中初始化
}, nil
}
func (s *APIServer) Start() error {
s.logger.Info("启动 MeshRay 服务器",
zap.String("mode", s.config.Server.Mode),
zap.Int("http_port", s.config.Server.Port))
// ========== P1: 启动 gRPC 服务器(为 Core 提供服务)==========
if err := s.startGRPCServer(); err != nil {
return fmt.Errorf("启动 gRPC 服务器失败:%w", err)
}
// ========== P2: 初始化 Ctr 并注入到 Service 层 ==========
var err error
s.ctrClient, err = ctr.NewCtr("default", 1, &ctr.CtrConfig{GRPCPort: 50051}, s.logger)
if err != nil {
s.logger.Error("初始化 meshray-ctr 失败", zap.Error(err))
panic(fmt.Sprintf("初始化 ctr 失败:%v", err))
}
// ... 后续 Service 层初始化 ...
// ========== P3: 启动 HTTP 服务器 ==========
addr := fmt.Sprintf(":%d", s.config.Server.Port)
if err := s.engine.Run(addr); err != nil {
return fmt.Errorf("启动 HTTP 服务器失败:%w", err)
}
return nil
}
// startGRPCServer 启动 gRPC 服务器(为 Core 提供服务)
func (s *APIServer) startGRPCServer() error {
s.logger.Info("正在启动 gRPC 服务器",
zap.Int("port", 50051))
// 1. 创建 Core 实例(作为库)
s.coreInst = core.NewCore(s.logger)
// 2. 创建 gRPC 服务器
lis, err := net.Listen("tcp", ":50051")
if err != nil {
return fmt.Errorf("无法监听 50051 端口:%w", err)
}
s.grpcServer = grpc.NewServer()
// 3. 注册 Core 服务(使用 core/grpc_service.go
coreService := core.NewCoreServiceServer(s.coreInst, s.logger)
core.RegisterCoreService(s.grpcServer, coreService)
// 4. 在后台启动 gRPC 服务器
go func() {
s.logger.Info("gRPC 服务器已启动",
zap.Int("port", 50051),
zap.String("service", "CoreService"))
if err := s.grpcServer.Serve(lis); err != nil {
s.logger.Error("gRPC 服务器错误", zap.Error(err))
}
}()
// 5. 等待 gRPC 服务器就绪(最多 3 秒)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
conn, err := grpc.DialContext(ctx, "127.0.0.1:50051", grpc.WithInsecure())
if err != nil {
return fmt.Errorf("gRPC 服务器未就绪:%w", err)
}
conn.Close()
s.logger.Info("gRPC 服务器验证成功")
return nil
}
// Stop 停止服务器
func (s *APIServer) Stop() error {
s.logger.Info("正在停止 MeshRay 服务器...")
// 1. 停止 Ctr
if s.ctrClient != nil {
if err := s.ctrClient.Stop(); err != nil {
s.logger.Error("停止 Ctr 失败", zap.Error(err))
}
}
// 2. 停止 gRPC 服务器
if s.grpcServer != nil {
s.grpcServer.GracefulStop()
}
// 3. 停止 Core 实例
if s.coreInst != nil {
// TODO: Core 实例清理
}
s.logger.Info("MeshRay 服务器已停止")
return nil
}
```
---
### **步骤 2: 验证修复**
```bash
# 编译项目
cd e:\Project\MeshRay
go build -o meshray.exe
# 运行测试
./meshray.exe serve
# 预期输出:
# [INFO] 正在启动 gRPC 服务器 port=50051
# [INFO] gRPC 服务器已启动 port=50051 service=CoreService
# [INFO] gRPC 服务器验证成功
# [INFO] 启动 MeshRay 服务器 mode=release http_port=8080
```
---
### **步骤 3: 删除未使用文件**
```bash
# 删除未使用的文件
rm internal/ctr/wg_manager.go
rm internal/ctr/wg_go_process.go
rm core/pool/connpool.go
rm pkg/meshseed/meshseed.go
# 保留 watchdog.go(标记为未来功能)
# 在 internal/ctr/watchdog.go 顶部添加注释:
// ⏳ TODO: 启用 Watchdog 监控功能
```
---
### **步骤 4: 注入 SystemConfigService**
```go
// internal/api/server.go:178 后添加
// 初始化 SystemConfigService
s.systemConfigService = service.NewSystemConfigService(s.store, s.logger)
```
---
### **步骤 5: 清理未使用常量/函数**
编辑以下文件,删除未使用的定义:
1. `internal/ctr/types.go:25` - 删除 `ErrCodeWGModeUnavailable`
2. `internal/service/network.go:208` - 删除 `generateNetworkSecret`
3. `internal/ctr/wg_detect.go:154` - 删除 `GetRecommendedWGMode`
---
## 📊 修复后的架构
```
┌─────────────────────────────────────┐
│ APIServer │
│ │
│ ┌──────────────────────────────┐ │
│ │ gRPC Server (:50051) │ │
│ │ ┌────────────────────────┐ │ │
│ │ │ CoreServiceServer │ │ │
│ │ │ - CreateEngine │ │ │
│ │ │ - Start │ │ │
│ │ │ - Stop │ │ │
│ │ │ - GetStatus │ │ │
│ │ └────────────────────────┘ │ │
│ └──────────────────────────────┘ │
│ ↑ │
│ │ gRPC 调用 │
│ ↓ │
│ ┌──────────────────────────────┐ │
│ │ Ctr (调度中心) │ │
│ │ ┌────────────────────────┐ │ │
│ │ │ CoreClient │ │ │
│ │ │ - 连接到 127.0.0.1:50051│ │ │
│ │ └────────────────────────┘ │ │
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ WGManager │ │
│ │ - tunDevice 引用 │ │
│ │ - wgDevice 引用 │ │
│ │ - 跨平台支持 │ │
│ └──────────────────────────────┘ │
└─────────────────────────────────────┘
│ HTTP/REST API
┌─────────────────────────────────────┐
│ Web UI (Vue 3) │
└─────────────────────────────────────┘
```
---
## 📋 验收清单
### **核心功能**
- ✅ gRPC 服务器成功启动在 50051 端口
- ✅ CoreClient 成功连接到 gRPC 服务器
-`CreateEngine` gRPC 调用返回成功
-`Start` gRPC 调用返回成功
- ✅ 日志显示完整的启动流程
### **代码清理**
- ✅ 删除 4 个未使用文件
- ✅ 删除 4 个未使用常量/函数
- ✅ SystemConfigService 正确注入
### **文档完善**
- ✅ 5 个预留模型都有注释
- ✅ 架构文档反映真实实现
---
## 🎯 总结
### **问题根源**
- ❌ Ctr 只有 Core 客户端,没有服务端
-`core/grpc_service.go` 的实现无处可用
- ❌ CoreClient 连接 127.0.0.1:50051 会失败
### **修复方案**
- ✅ 在 APIServer 中启动 gRPC 服务器
- ✅ 使用 `core/grpc_service.go` 的实现
- ✅ Core 作为库集成到进程中
### **技术价值**
- ✅ 解决了核心架构问题
- ✅ 使 Core 层功能真正可用
- ✅ 统一了进程内通信
- ✅ 简化了部署流程
---
**修复完成时间**: 预计 2-3 小时
**状态**: 📋 **等待实施**
**优先级**: 🔴 **P0 - 必须立即修复**