Initial commit
This commit is contained in:
@@ -0,0 +1,489 @@
|
||||
# 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 - 必须立即修复**
|
||||
Reference in New Issue
Block a user