Skip to content

Commit

Permalink
Merge branch 'master' into feat/tinghean2
Browse files Browse the repository at this point in the history
  • Loading branch information
tinghean committed Sep 2, 2023
2 parents ab11a1b + ca9232a commit e9d03ed
Show file tree
Hide file tree
Showing 47 changed files with 3,412 additions and 277 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/StandAloneDouyin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go

name: StandAloneDouyin

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.19'

- name: Set up and start MySQL
run: |
sudo apt-get install -y mysql-server
sudo service mysql start
- name: Try connect to MySQL
run: |
sudo mysql -uroot -proot
- name: Start Redis
uses: supercharge/[email protected]
with:
redis-port: 6379

- name: start test
run: |
cd tests
bash ./start_douyin.sh
go test ./integration
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ _testmain.go
/output
*.local.yml
dumped_hertz_remote_config.json

douyin

153 changes: 0 additions & 153 deletions biz/handler/api/websocket_service.go

This file was deleted.

3 changes: 3 additions & 0 deletions biz/mw/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ func JWT() app.HandlerFunc {
if token == "" {
token = c.PostForm("token")
}
if token == "" {
token = c.Request.Header.Get("token")
}
if token == "" {
hlog.Error("mw.jwt.ParseToken err:", errno.UserIdentityVerificationFailedError)
c.JSON(consts.StatusOK, &api.DouyinResponse{
Expand Down
3 changes: 2 additions & 1 deletion biz/router/api/api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

97 changes: 95 additions & 2 deletions biz/service/comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,30 @@ import (
"douyin/dal/db"
"douyin/dal/pack"
"douyin/pkg/errno"
"douyin/pkg/global"
"douyin/pkg/util/sensitive"
"fmt"
"github.com/bits-and-blooms/bloom/v3"
"github.com/cloudwego/hertz/pkg/common/hlog"
"github.com/cloudwego/hertz/pkg/common/json"
"math/rand"
"strconv"
"sync"
"time"
)

// Global variables for cache status flag and Bloom filter
var (
cacheMutex sync.Mutex
cacheStatus map[string]*sync.WaitGroup
bloomFilter *bloom.BloomFilter
)

func init() {
cacheStatus = make(map[string]*sync.WaitGroup)
bloomFilter = bloom.NewWithEstimates(1000000, 0.01)
}

func PostComment(userID, videoID uint64, commentText string) (*api.DouyinCommentActionResponse, error) {
// 删除redis评论列表缓存
// 使用 strings.Builder 来优化字符串的拼接
Expand Down Expand Up @@ -40,6 +60,10 @@ func PostComment(userID, videoID uint64, commentText string) (*api.DouyinComment
return nil, err
}

// Notify cache invalidation
// Publish a message to the Redis channel indicating a comment list change
global.UserInfoRC.Publish("commentList_changes", "comment_added"+"&"+strconv.FormatUint(userID, 10)+"&"+strconv.FormatUint(videoID, 10))

return &api.DouyinCommentActionResponse{
StatusCode: 0,
Comment: pack.Comment(dbc, dbu, db.IsFollow(userID, authorID)),
Expand Down Expand Up @@ -71,19 +95,88 @@ func DeleteComment(userID, videoID, commentID uint64) (*api.DouyinCommentActionR
return nil, err
}

// Notify cache invalidation
// Publish a message to the Redis channel indicating a comment list change
global.UserInfoRC.Publish("commentList_changes", "comment_deleted"+"&"+strconv.FormatUint(userID, 10)+"&"+strconv.FormatUint(videoID, 10))

return &api.DouyinCommentActionResponse{
StatusCode: 0,
Comment: pack.Comment(dbc, dbu, db.IsFollow(userID, authorID)),
}, nil
}

func GetCommentList(userID, videoID uint64) (*api.DouyinCommentListResponse, error) {
// Check if comment data is available in Redis cache
cacheKey := fmt.Sprintf("commentList:%d:%d", userID, videoID)

// 解决缓存穿透 -- 添加布隆过滤器判断值是否在于RC或DB
if bloomFilter.TestString(cacheKey) {
cachedData, err := global.UserInfoRC.Get(cacheKey).Result()
if err == nil {
// Cache hit, return cached comment data
var cachedResponse api.DouyinCommentListResponse
if err := json.Unmarshal([]byte(cachedData), &cachedResponse); err != nil {
hlog.Error("service.comment.GetCommentList err: Error decoding cached data, ", err.Error())
} else {
return &cachedResponse, nil
}
}
}

// 解决缓存击穿 -- 添加互斥锁,同一时间仅有一个线程更新缓存
// Create a WaitGroup for the cache update operation
waitGroup := &sync.WaitGroup{}
waitGroup.Add(1)

// Check if another thread is updating the cache
cacheMutex.Lock()
existingWaitGroup, exists := cacheStatus[cacheKey]
if exists {
cacheMutex.Unlock()
existingWaitGroup.Wait()
return GetCommentList(userID, videoID)
}
// Set cache status flag to indicate cache update is in progress
cacheStatus[cacheKey] = waitGroup
cacheMutex.Unlock()

// Cache miss, query the database
commentData, err := db.SelectCommentDataByVideoIDANDUserID(videoID, userID)
if err != nil {
hlog.Error("service.comment.GetCommentList err:", err.Error())
// Release cache status flag to allow other threads to update cache
cacheMutex.Lock()
delete(cacheStatus, cacheKey)
cacheMutex.Unlock()
return nil, err
}
return &api.DouyinCommentListResponse{

// Convert to response format
response := &api.DouyinCommentListResponse{
StatusCode: 0,
CommentList: pack.CommentDataList(commentData),
}, nil
}

// Store comment data in Redis cache
responseJSON, _ := json.Marshal(response)

// 解决缓存雪崩 -- 添加随机数,避免缓存同时过期
// Add a random duration to the cache valid time
cacheDuration := 10*time.Minute + time.Duration(rand.Intn(600))*time.Second

err = global.UserInfoRC.Set(cacheKey, responseJSON, cacheDuration).Err()
if err != nil {
hlog.Error("service.comment.GetCommentList err: Error storing data in cache, ", err.Error())
}

// Add cacheKey to Bloom filter
bloomFilter.AddString(cacheKey)

// Release cache status flag and signal that cache update is done
cacheMutex.Lock()
delete(cacheStatus, cacheKey)
waitGroup.Done()
cacheMutex.Unlock()

return response, nil
}
Loading

0 comments on commit e9d03ed

Please sign in to comment.