Skip to content

RhythmicWave/LinkBook

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LinkBook

基于 Go 的高并发内容社区平台,采用 Gin + GORM + MySQL + Redis + Kafka 技术栈,前端使用 React + Ant Design。

技术栈

层级 技术
Web 框架 Gin
ORM GORM
数据库 MySQL
缓存 Redis
消息队列 Kafka
依赖注入 Wire
前端 React + TypeScript + Ant Design
部署 Docker Compose

项目架构

graph TB
    subgraph Frontend
        React[React + Ant Design]
    end

    subgraph Web Layer
        Gin[Gin Router]
        JWT[JWT 认证]
        RateLimit[滑动窗口限流]
        VO[VO 转换]
    end

    subgraph Service Layer
        BizLogic[业务逻辑]
        Validation[参数校验]
    end

    subgraph Event Layer
        Producer[Kafka Producer]
        Consumer[Kafka Consumer<br/>批量消费]
    end

    subgraph Repository Layer
        RepoLogic[缓存策略 · 数据组装 · 降级处理]
    end

    subgraph Storage
        Cache[Redis<br/>Lua 脚本 · Pipeline]
        DAO[MySQL<br/>批量 SQL · 复合索引]
        LocalCache[本地缓存<br/>atomic 无锁读]
    end

    React -->|HTTP/JSON| Gin
    Gin --> JWT --> RateLimit --> VO --> BizLogic
    BizLogic --> Validation
    BizLogic --> Producer
    Producer --> Consumer
    Consumer --> RepoLogic
    BizLogic --> RepoLogic
    RepoLogic --> Cache
    RepoLogic --> DAO
    RepoLogic --> LocalCache
Loading

分层设计

项目严格遵循六层架构,各层职责清晰,通过接口解耦:

backend/internal/
├── domain/          # 领域模型:纯数据结构 + 业务错误定义
├── repository/
│   ├── dao/         # 数据访问:GORM 操作,SQL 构建
│   └── cache/       # 缓存访问:Redis 操作,Lua 脚本
├── repository/      # 仓储层:组合 Cache + DAO,缓存策略,数据转换
├── service/         # 业务层:核心业务逻辑,参数校验
├── web/             # 接口层:路由,请求/响应 VO,中间件
├── events/          # 事件层:Kafka Producer/Consumer
├── job/             # 定时任务:热榜计算,分布式锁
└── ioc/             # 依赖注入:Wire 初始化

核心功能模块

1. 用户系统

  • 注册、登录(手机验证码 / 邮箱密码)
  • JWT 双 Token 认证(Access Token + Refresh Token)
  • 微信 OAuth2 第三方登录

2. 文章系统

  • 文章创作、编辑、发布、撤回
  • 制作库 / 线上库分离(读写分离预备)
  • 富文本编辑器(WangEditor)

3. 互动系统

  • 点赞、收藏、阅读计数
  • Kafka 异步削峰(详见下方亮点)
  • Redis 缓存互动数据

4. 评论系统

  • 一级评论 + 嵌套回复(楼中楼)
  • 回复预览 + 分页加载
  • 批量查询解决 N+1 问题(41 次 SQL → 3 次)
  • 软删除,防御性校验

5. 热榜系统

  • 定时任务 + 分布式锁(防止多实例重复计算)
  • 时间衰减热度算法(Hacker News 风格)
  • 游标分页遍历全量文章 + 小顶堆 Top N
  • Redis 缓存 + 本地缓存(atomic 无锁读)+ ForceGet 兜底

6. 短信服务

  • 装饰器模式:限流、重试、failover、监控可自由组合
  • 超时 failover 自动切换服务商(atomic CAS)
  • DB 抢占式异步重试(SELECT FOR UPDATE + 重试上限)
  • JWT 模板鉴权,防止调用方使用任意模板

7. 基础设施

  • Redis Lua 脚本保证原子性
  • 滑动窗口限流(按用户 ID)
  • Prometheus 监控指标

技术亮点

亮点一:Kafka 异步削峰架构

将阅读计数、点赞、收藏等高频写操作从同步写 DB 改造为 Kafka 异步处理。

flowchart LR
    A[用户操作] --> B[Service<br/>发送 Kafka 消息]
    B --> C[立即返回]
    B --> D[Kafka Broker]
    D --> E[Consumer<br/>批量消费 100条/批]
    E --> F[Redis Pipeline<br/>批量去重]
    F --> G[批量写入 MySQL<br/>ON DUPLICATE KEY UPDATE]
    G --> H[异步更新<br/>Redis 缓存]
Loading

关键设计:

  • 自定义 BatchHandler 框架,支持批量消费,将 100 次 DB 交互合并为 1 次
  • 阅读计数使用 Redis Pipeline + SetNX 实现分布式去重,100 次网络往返合并为 1 次
  • 点赞/收藏使用 ON CONFLICT DO UPDATE SET status=? 实现幂等 upsert
  • 事务包装双表更新(用户行为表 + 互动统计表),保证数据一致性
  • 按 bizId 聚合计数,减少 Interactive 表的更新次数

性能收益: 接口响应时间大幅降低,数据库写入压力从峰值 QPS 平滑到平均 QPS。

亮点二:热榜系统完整实现

从定时触发到结果展示的完整热榜链路:

flowchart TB
    Cron[Cron 定时触发] --> Lock{抢分布式锁<br/>redis-lock}
    Lock -->|成功| Refresh[AutoRefresh<br/>自动续约]
    Lock -->|失败| Skip[跳过本轮]
    Refresh --> Cursor[游标分页遍历<br/>WHERE id > lastId<br/>+ 7天时间过滤]
    Cursor --> Score[热度计算<br/>score = likeCnt-1 / pow duration+2 1.5]
    Score --> Heap[小顶堆<br/>维护 Top 100]
    Heap --> Redis[(Redis 缓存<br/>TTL 3min)]
    Redis --> Local[(本地缓存<br/>atomic 无锁读)]
    Local --> API[GetTopN API]
    Redis -.->|Redis 不可用| ForceGet[ForceGet<br/>忽略过期时间<br/>兜底返回]
Loading

关键设计:

  • 分布式锁 + AutoRefresh 续约:多实例部署时只有一个节点执行计算,锁持有期间自动续约防止超时释放
  • 游标分页:WHERE id > lastId ORDER BY id ASC,避免 OFFSET 深度分页的性能退化
  • SQL 层 7 天时间过滤:WHERE utime >= 7天前,将候选集从百万级缩减到万级
  • 复合索引 (status, utime, id):覆盖 WHERE + ORDER BY,避免回表
  • 小顶堆 Top N:内存中维护固定大小的优先队列,O(N log K) 时间复杂度
  • 多级缓存:Redis(3 分钟 TTL)→ 本地缓存(atomic 无锁读,零 GC 压力)→ ForceGet 兜底(Redis 故障时忽略过期时间返回旧数据)

亮点三:Redis Lua 脚本与滑动窗口限流

  • 用 Lua 脚本将 HSet + Expire 合并为原子操作,解决进程崩溃导致缓存 key 永久残留的问题
  • 实现滑动窗口限流算法(ZSet 存储请求时间戳),为互动接口提供按用户 ID 的防刷保护
  • 限流中间件在 IOC 层初始化,Handler 层通过依赖注入接收,符合分层架构

亮点四:短信服务架构设计

基于装饰器模式实现可组合的短信服务,各层职责独立,自由嵌套:

flowchart TB
    Caller[业务调用方] --> OTel[OpenTelemetry<br/>链路追踪]
    OTel --> Prom[Prometheus<br/>发送耗时监控]
    Prom --> Auth[JWT Auth<br/>模板 ID 鉴权]
    Auth --> Limit{滑动窗口限流}
    Limit -->|未限流| Async[异步重试服务]
    Limit -->|触发限流| Reject[拒绝发送]
    Async -->|同步发送| Failover[Timeout Failover]
    Async -->|异步入库| DB[(MySQL<br/>async_sms 表)]
    DB -->|抢占式调度| Failover
    Failover -->|atomic CAS<br/>切换服务商| Provider1[腾讯云 SMS]
    Failover --> Provider2[备用服务商]
Loading

关键设计:

  • 装饰器模式:所有组件实现同一个 sms.Service 接口,限流、重试、failover、监控可自由组合嵌套
  • 超时 Failover:用 atomic.CompareAndSwapInt32 追踪连续超时次数,超过阈值自动切换到下一个服务商,无锁实现
  • DB 抢占式异步重试:SELECT ... FOR UPDATE 抢占待发送记录,utime 间隔 1 分钟防止重复抢占,retry_cnt 达到上限后标记失败
  • JWT 模板鉴权:调用方传入的 tplId 实际是 JWT Token,服务端解析后提取真实模板 ID,防止调用方使用任意模板

项目结构

linkbook/
├── backend/                    # Go 后端
│   ├── main.go                # 入口
│   ├── wire.go                # Wire 依赖注入定义
│   ├── internal/
│   │   ├── domain/            # 领域模型
│   │   ├── repository/
│   │   │   ├── dao/           # MySQL 数据访问
│   │   │   └── cache/         # Redis 缓存
│   │   │       └── lua/       # Lua 脚本
│   │   ├── service/           # 业务逻辑
│   │   ├── web/               # HTTP 接口 + VO
│   │   ├── events/            # Kafka 事件处理
│   │   └── job/               # 定时任务
│   ├── ioc/                   # IOC 初始化(DB/Redis/Kafka/Web)
│   ├── pkg/                   # 通用工具包
│   │   ├── ginx/              # Gin 扩展(统一响应、中间件)
│   │   ├── limiter/           # 限流器(滑动窗口)
│   │   ├── samarax/           # Kafka 批量消费框架
│   │   └── logger/            # 日志抽象
│   └── docker-compose.yaml    # 本地开发环境
│
└── frontend/                  # React 前端
    └── src/
        ├── components/        # 通用组件(评论、编辑器、布局)
        ├── pages/             # 页面(首页、文章、用户)
        └── types/             # TypeScript 类型定义

本地运行

环境要求

  • Go 1.21+
  • Node.js 18+
  • Docker & Docker Compose

启动步骤

# 1. 启动基础设施(MySQL、Redis、Kafka)
cd backend
docker-compose up -d

# 2. 启动后端
go run main.go

# 3. 启动前端
cd ../frontend
npm install
npm run dev

About

基于 Go 的内容社区平台

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages