Skip to content

raaaaap/SwiftFeed

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

1 Commit
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

SwiftFeed

็Ÿญ่ง†้ข‘ๅ†…ๅฎนๅˆ†ๅ‘็ณป็ปŸ

License: MIT Go Gin Redis RabbitMQ Docker


้ซ˜ๆ€ง่ƒฝ็Ÿญ่ง†้ข‘ Feed ๆต็ณป็ปŸ
ๅŸบไบŽ Go ๆž„ๅปบ๏ผŒ้‡‡็”จไธ‰็บง็ผ“ๅญ˜ๆžถๆž„ใ€ๅผ‚ๆญฅไบ‹ไปถ้ฉฑๅŠจไธŽๆŽจๆ‹‰ๆททๅˆๅˆ†ๅ‘็ญ–็•ฅ
ๅ•ๆœบ 6890 QPS๏ผŒP99 ๅ“ๅบ” 8.4ms


โœจ ๆ ธๅฟƒ็‰นๆ€ง

๐Ÿš€ ้ซ˜ๆ€ง่ƒฝ Feed ๅˆ†ๅ‘

ๅœบๆ™ฏ ็ญ–็•ฅ ๆ€ง่ƒฝ
Timeline ๆ—ถ้—ดๆŽ’ๅบ + ไธ‰็บง็ผ“ๅญ˜ + Singleflight ้˜ฒๅ‡ป็ฉฟ P99 8.4ms
Hot Redis ZSET ๆป‘ๅŠจ็ช—ๅฃๅฎžๆ—ถ่šๅˆ QPS 4190
Following ๆŽจๆ‹‰ๆททๅˆ๏ผˆ10k ็ฒ‰ไธ้˜ˆๅ€ผ๏ผ‰ P99 8.4ms
Recommend ไฝ™ๅผฆ็›ธไผผๅบฆ + ็ƒญๅบฆ + ๆ–ฐ้ฒœๅบฆๅคšไฟกๅทๆŽ’ๅบ P99 8.4ms

โšก ๅผ‚ๆญฅไบ’ๅŠจๆตๆฐด็บฟ

็”จๆˆท็‚น่ตž โ†’ Redis ๅฟซๅ†™๏ผˆไน่ง‚้”๏ผ‰ โ†’ RabbitMQ ๅผ‚ๆญฅ โ†’ Worker ่ฝๅบ“ MySQL
                                    โ†“
                              MQ ๆ•…้šœ่‡ชๅŠจ้™็บงไธบๅŒๆญฅๅ†™ๅ…ฅ
  • 16 ๅˆ†็‰‡่ฎกๆ•ฐๅ™จ โ€” ๆŒ‰ user_id ๅˆ†ๆ•ฃ็ƒญ็‚นๅ†™ๅ…ฅ
  • WATCH + TxPipeline โ€” Redis ไน่ง‚้”ไฟ่ฏๅนถๅ‘ๅฎ‰ๅ…จ
  • ๅน‚็ญ‰้”ฎ โ€” ้˜ฒๆญข้‡ๅคๆ“ไฝœ
  • ่‡ชๅŠจ้™็บง โ€” MQ ๆ•…้šœๆ—ถๅŒๆญฅ็›ดๅ†™ MySQL

๐ŸŽฏ ไธชๆ€งๅŒ–ๆŽจ่

  • ้›ถไพ่ต–ๅ‘้‡ๅŒ– โ€” ๅ“ˆๅธŒ N-gram 128 ็ปดๅ‘้‡๏ผŒๆ— ้œ€ๅค–้ƒจ ML ๆœๅŠก
  • ๅคšไฟกๅทๆŽ’ๅบ โ€” 70% ็›ธไผผๅบฆ + 20% ็ƒญๅบฆ + 10% ๆ–ฐ้ฒœๅบฆ
  • ๅ†ทๅฏๅŠจ้™็บง โ€” ๆ— ็”จๆˆทๅ‘้‡ๆ—ถ 65% ็ƒญๅบฆ + 35% ๆ–ฐ้ฒœๅบฆ
  • 7 ๅคฉๆ›ๅ…‰ๅŽป้‡ โ€” ้˜ฒๆญขๅ†…ๅฎน้‡ๅคๆŽจ่

๐Ÿ“ฆ ๆŽจๆ‹‰ๆททๅˆ Fanout

็ฒ‰ไธ้‡็บง ็ญ–็•ฅ ๅ†™ๅ…ฅๆˆๆœฌ ่ฏปๅ–ๆˆๆœฌ
< 10k ๆŽจ้€ๅˆฐ็ฒ‰ไธ inbox O(็ฒ‰ไธๆ•ฐ) O(1)
โ‰ฅ 10k ๅ†™ๅ…ฅไฝœ่€… outbox O(1) O(ๅ…ณๆณจ็š„ๅคงVๆ•ฐ)

๐Ÿ—๏ธ ๆžถๆž„

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                      React Web Client                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                          โ”‚ HTTP
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                     Gin HTTP Server                          โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”‚
โ”‚  โ”‚ Account  โ”‚ โ”‚  Video   โ”‚ โ”‚  Feed    โ”‚ โ”‚Interactionโ”‚  ...  โ”‚
โ”‚  โ”‚ Handler  โ”‚ โ”‚ Handler  โ”‚ โ”‚ Handler  โ”‚ โ”‚ Handler  โ”‚       โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜       โ”‚
โ”‚       โ”‚            โ”‚            โ”‚            โ”‚               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”        โ”‚
โ”‚  โ”‚              Application Layer                    โ”‚        โ”‚
โ”‚  โ”‚  Service (Business Logic + Strategy Pattern)      โ”‚        โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜        โ”‚
โ”‚       โ”‚            โ”‚            โ”‚            โ”‚               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”‚
โ”‚  โ”‚  MySQL   โ”‚ โ”‚  Redis   โ”‚ โ”‚ RabbitMQ โ”‚ โ”‚  GORM    โ”‚      โ”‚
โ”‚  โ”‚ (11 tables)โ”‚ โ”‚(Multi-level)โ”‚ โ”‚ (Async) โ”‚ โ”‚(Persist) โ”‚      โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                          โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Worker Process                            โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                    โ”‚
โ”‚  โ”‚ Action   โ”‚ โ”‚ Fanout   โ”‚ โ”‚ Embeddingโ”‚                    โ”‚
โ”‚  โ”‚ Worker   โ”‚ โ”‚ Worker   โ”‚ โ”‚ Worker   โ”‚                    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ“Š ๆ€ง่ƒฝๅŸบๅ‡†

ๆŒ‡ๆ ‡ ๆ•ฐๅ€ผ ่ฏดๆ˜Ž
Feed ่ฏปๅ– QPS 6,890 ๅ•ๆœบ 20 ๅนถๅ‘
Feed ่ฏปๅ– P99 8.4ms ไธ‰็บง็ผ“ๅญ˜ + ๆธธๆ ‡ๅˆ†้กต
ไบ’ๅŠจๅ†™ๅ…ฅ Avg 74ms Redis ๅฟซๅ†™ + MQ ๅ‘ๅธƒ
ๅผ‚ๆญฅ่ฝๅบ“ๅปถ่ฟŸ ~2s MQ ๆถˆ่ดนๅฎŒๆˆ

๐Ÿš€ ๅฟซ้€ŸๅฏๅŠจ

Docker Compose

# ๅ…‹้š†้กน็›ฎ
git clone https://github.com/raaaaap/SwiftFeed.git
cd SwiftFeed/apps

# ๅฏๅŠจๆ‰€ๆœ‰ๆœๅŠก
docker compose up -d --build

# ๆŸฅ็œ‹ๆ—ฅๅฟ—
docker compose logs -f api web

ๆœๅŠกๅœฐๅ€

ๆœๅŠก ๅœฐๅ€
Web http://127.0.0.1:5173
API http://127.0.0.1:8080
API ๅฅๅบทๆฃ€ๆŸฅ http://127.0.0.1:8080/health
MySQL 127.0.0.1:3307
Redis 127.0.0.1:6379
RabbitMQ ็ฎก็†ๅฐ http://127.0.0.1:15672

ๆœฌๅœฐๅผ€ๅ‘

./scripts/start.sh

๐Ÿ“ ้กน็›ฎ็ป“ๆž„

apps/api/internal/
โ”œโ”€โ”€ application/           # ๅบ”็”จๅฑ‚๏ผˆไธšๅŠก้€ป่พ‘๏ผ‰
โ”‚   โ”œโ”€โ”€ feed/              # Feed ๆตๆœๅŠก๏ผˆ็ญ–็•ฅๆจกๅผ + ๅคš็บง็ผ“ๅญ˜๏ผ‰
โ”‚   โ”œโ”€โ”€ interaction/       # ไบ’ๅŠจๆœๅŠก๏ผˆๅผ‚ๆญฅๆตๆฐด็บฟ๏ผ‰
โ”‚   โ”œโ”€โ”€ recommendation/    # ๆŽจ่ๆœๅŠก๏ผˆๅ‘้‡ๅŒ– + ๆŽ’ๅบ๏ผ‰
โ”‚   โ”œโ”€โ”€ video/             # ่ง†้ข‘ๆœๅŠก๏ผˆFanout Worker๏ผ‰
โ”‚   โ””โ”€โ”€ relation/          # ็คพไบคๅ…ณ็ณป๏ผˆๆŽจๆ‹‰ๆททๅˆๅˆ†ๅ‘๏ผ‰
โ”œโ”€โ”€ domain/                # ้ข†ๅŸŸๅฑ‚๏ผˆๅฎžไฝ“ + ๆŽฅๅฃ๏ผ‰
โ”‚   โ”œโ”€โ”€ feed/              # Feed ้ข†ๅŸŸๆจกๅž‹
โ”‚   โ”œโ”€โ”€ interaction/       # ไบ’ๅŠจ้ข†ๅŸŸๆจกๅž‹
โ”‚   โ””โ”€โ”€ embedding/         # ๅ‘้‡ๅŒ–๏ผˆๅ“ˆๅธŒ N-gram๏ผ‰
โ””โ”€โ”€ infra/                 # ๅŸบ็ก€่ฎพๆ–ฝๅฑ‚
    โ”œโ”€โ”€ cache/             # Redis ็ผ“ๅญ˜ๅฎž็Žฐ
    โ”œโ”€โ”€ mq/                # RabbitMQ ๅฎขๆˆท็ซฏ
    โ”œโ”€โ”€ persistence/       # GORM ๆŒไน…ๅŒ–
    โ””โ”€โ”€ database/          # ๆ•ฐๆฎๅบ“่ฟžๆŽฅ

๐Ÿ”ง ๆŠ€ๆœฏๆ ˆ

็ฑปๅˆซ ๆŠ€ๆœฏ ่ฏดๆ˜Ž
่ฏญ่จ€ Go ้ซ˜ๅนถๅ‘ใ€้™ๆ€็ผ–่ฏ‘ใ€้ƒจ็ฝฒ็ฎ€ๅ•
Web ๆก†ๆžถ Gin ่ทฏ็”ฑๆ€ง่ƒฝๅฅฝใ€ไธญ้—ดไปถ็ตๆดป
ORM GORM ่‡ชๅŠจ่ฟ็งปใ€้’ฉๅญๅ‡ฝๆ•ฐใ€้ข„ๅŠ ่ฝฝ
ๆ•ฐๆฎๅบ“ MySQL 8.4 InnoDBใ€ไบ‹ๅŠก่กŒ้”ใ€B+ ๆ ‘็ดขๅผ•
็ผ“ๅญ˜ Redis 7.4 ZSET ็ƒญๆฆœใ€HASH ่ฎกๆ•ฐใ€Pipeline ๆ‰น้‡ๆ“ไฝœ
ๆถˆๆฏ้˜Ÿๅˆ— RabbitMQ 3.13 Topic Exchangeใ€ๆŒไน…ๅŒ–ใ€ๆ‰‹ๅŠจ ACK
ๅฎนๅ™จๅŒ– Docker + Compose ๅคš้˜ถๆฎตๆž„ๅปบใ€ๅฅๅบทๆฃ€ๆŸฅใ€ไผ˜้›…ๅ…ณ้—ญ
ๅ‰็ซฏ React 18 + Vite 5 ๅž‚็›ดๆป‘ๅŠจใ€ๆ›ๅ…‰่ฟฝ่ธชใ€ๆš—่‰ฒไธป้ข˜

๐Ÿ“– API ๆŽฅๅฃ

Feed

GET  /api/feed-items?scene=timeline&limit=10&cursor=xxx
POST /api/feed-queries  (JSON body with scene, cursor, limit, context)

ไบ’ๅŠจ

PUT    /api/videos/:videoId/like          # ็‚น่ตž
DELETE /api/videos/:videoId/like          # ๅ–ๆถˆ็‚น่ตž
PUT    /api/videos/:videoId/favorite      # ๆ”ถ่—
DELETE /api/videos/:videoId/favorite      # ๅ–ๆถˆๆ”ถ่—
POST   /api/videos/:videoId/comments      # ่ฏ„่ฎบ
GET    /api/videos/:videoId/comments      # ่ฏ„่ฎบๅˆ—่กจ
DELETE /api/comments/:commentId           # ๅˆ ้™ค่ฏ„่ฎบ

็”จๆˆท

POST   /api/users                         # ๆณจๅ†Œ
POST   /api/sessions                      # ็™ปๅฝ•
GET    /api/users/me                      # ไธชไบบไฟกๆฏ
PATCH  /api/users/me                      # ๆ›ดๆ–ฐ่ต„ๆ–™

็คพไบค

PUT    /api/users/me/following/:targetId  # ๅ…ณๆณจ
DELETE /api/users/me/following/:targetId  # ๅ–ๆถˆๅ…ณๆณจ
GET    /api/users/me/following            # ๅ…ณๆณจๅˆ—่กจ
GET    /api/users/me/followers            # ็ฒ‰ไธๅˆ—่กจ

่ง†้ข‘

POST   /api/videos                        # ๅ‘ๅธƒ่ง†้ข‘
GET    /api/videos/:videoId               # ่ง†้ข‘่ฏฆๆƒ…
DELETE /api/videos/:videoId               # ๅˆ ้™ค่ง†้ข‘
GET    /api/users/me/videos               # ๆˆ‘็š„ไฝœๅ“

๐Ÿงช ๆต‹่ฏ•

# ่ฟ่กŒๆ‰€ๆœ‰ๆต‹่ฏ•
cd apps/api && go test ./test/ -v

# ่ฟ่กŒๅ•ๅ…ƒๆต‹่ฏ•
go test ./internal/domain/embedding/ -v
go test ./internal/infra/cache/ -v
go test ./internal/application/feed/ -v
go test ./internal/application/recommendation/ -v

# ๆ€ง่ƒฝๆต‹่ฏ•
hey -n 500 -c 20 "http://127.0.0.1:8080/api/feed-items?scene=timeline&limit=10"

๐Ÿ“š ๆ–‡ๆกฃ

ๆ–‡ๆกฃ ่ฏดๆ˜Ž
docs/product.md ไบงๅ“่Œƒๅ›ดใ€ๆจกๅ—ๅœฐๅ›พใ€P0/P1 ๅŠŸ่ƒฝๆธ…ๅ•
docs/architecture.md ็ณป็ปŸๆžถๆž„ใ€ๅˆ†ๅฑ‚ใ€ๆ ธๅฟƒ้“พ่ทฏใ€ๆ•ฐๆฎๆจกๅž‹
docs/engineering.md ๅทฅ็จ‹่ง„่Œƒใ€็›ฎๅฝ•่ง„ๅˆ™ใ€API ้ฃŽๆ ผใ€ๆต‹่ฏ•็บฆๅฎš
docs/optimization.md Feed ๆ€ง่ƒฝๅ’Œ็จณๅฎšๆ€งไธ“้ข˜
docs/modules/ ๅ„ไธšๅŠกๆจกๅ—่ฎพ่ฎก

๐Ÿ“„ License

MIT License โ€” see LICENSE for details.


Built with Go โค๏ธ