建站推广哪里有建站新闻资讯,徐州网站开发公司,网站建设维护百家号,投资加盟项目配置redis适用与golang云原生架构。包括redis与数据库一致性等重要内容
1、编写redis配置文件、使用viper读取
配置文件 db.yml
redis:addr: 127.0.0.1port: 6379password: tiktokRedisdb: 0 # 数据库编号读取配置文件
var (config viper.Init(db)zapL…配置redis适用与golang云原生架构。包括redis与数据库一致性等重要内容
1、编写redis配置文件、使用viper读取
配置文件 db.yml
redis:addr: 127.0.0.1port: 6379password: tiktokRedisdb: 0 # 数据库编号读取配置文件
var (config viper.Init(db)zapLogger zap.InitLogger()redisOnce sync.OnceredisHelper *RedisHelperFavoriteMutex *redsync.MutexRelationMutex *redsync.Mutex
)2、新建并初始化一个redisClient 新建 其中sync.Once 是 Go 标准库中提供的一个同步原语用于保证某个操作仅执行一次。 调用 redisOnce.Do() 方法传入一个函数作为参数。Do() 方法会判断该函数是否已经被执行过如果没有则执行该函数。在这个例子中函数中的代码如下 rdh : new(RedisHelper)
rdh.Client rdb
redisHelper rdh在这段代码中首先创建了一个 RedisHelper 对象并将 rdb 赋值给其中的 Client 字段。然后将 rdh 赋值给 redisHelper 变量。redisHelper 是一个全局变量用于保存单例实例。 通过这样的方式可以保证在多个并发请求中只有第一次执行 Do() 方法时会初始化 Redis 连接单例后续的请求都会直接返回已经初始化好的连接对象。
func NewRedisHelper() *redis.Client {rdb : redis.NewClient(redis.Options{Addr: fmt.Sprintf(%s:%s, config.Viper.GetString(redis.addr), config.Viper.GetString(redis.port)),Password: config.Viper.GetString(redis.password),DB: config.Viper.GetInt(redis.db),DialTimeout: 10 * time.Second,ReadTimeout: 30 * time.Second,WriteTimeout: 30 * time.Second,//MaxConnAge: 1 * time.Minute, go-redis v9 已删去PoolSize: 10,PoolTimeout: 30 * time.Second,})redisOnce.Do(func() {rdh : new(RedisHelper)rdh.Client rdbredisHelper rdh})return rdb
}初始化 为什么需要传入 ctx 控制请求的超时和取消通过传入 ctx可以设置请求的超时时间当超过指定时间后可以自动取消请求避免无限等待。这对于处理网络请求或长时间运行的操作非常重要可以确保你的程序具有良好的健壮性并能及时释放资源。 传递请求特定的值ctx 可以用于在请求的不同组件之间传递请求特定的值如身份验证令牌、用户信息等。通过使用 ctx可以将这些值以一种可靠且类型安全的方式传递给相关的函数和方法。 协调并发请求在并发请求的场景中ctx 可以用于协调各个请求的完成状态。你可以通过 ctx 来等待所有请求完成或收集并汇总结果。
func init() {ctx : context.Background()rdb : NewRedisHelper()//典型测试连接的代码if _, err : rdb.Ping(ctx).Result(); err ! nil {zapLogger.Fatalln(err.Error())return}zapLogger.Info(Redis server connection successful!)// 开启定时同步至数据库GoCronFavorite()GoCronRelation()zapLogger.Info(MySQL synchronization is enabled.)// Redis锁// 创建Redis连接池pool : goredis.NewPool(rdb)// Create an instance of redisync to be used to obtain a mutual exclusion lock.rs : redsync.New(pool)// Obtain a new mutex by using the same name for all instances wanting the same lock.FavoriteMutex rs.NewMutex(mutex-favorite)RelationMutex rs.NewMutex(mutex-relation)
}3. redis和mysql的一致性
使用定时同步的思想将redis中的数据定时同步到数据库中
3.1 异步定时任务的执行
具体做法
使用了 GoCron 库来创建一个定时任务每隔一定频率执行 RedisDataMoveToDB 函数。首先通过 gocron.NewSchedule() 创建了一个调度器对象 s。接下来调用 s.Every(frequency) 方法设置定时任务的执行频率frequency 是一个时间间隔。这里使用 .Seconds() 方法表示以秒为单位进行间隔设置。然后通过 .Tag(“favoriteRedis”) 方法给定时任务添加了一个标签用于标识该任务以便后续操作或管理。最后调用 .Do(FavoriteMoveToDB) 方法指定定时任务要执行的函数为 FavoriteMoveToDB即在每个频率间隔结束时执行该函数。最后一行的 s.StartAsync() 表示以异步方式开始执行定时任务。这会启动一个新的 goroutine 来执行定时任务而不会阻塞当前的程序执行。这样可以保证定时任务在后台按照设定的频率执行而不会影响主程序的执行。
func GoCronFavorite() {s : gocron.NewSchedule()s.Every(frequency).Tag(favoriteRedis).Seconds().Do(FavoriteMoveToDB)s.StartAsync()
}
其中使用到的gocron
// Schedule 定时任务 gocron
type Schedule struct {*gocron.Scheduler
}
func NewSchedule() *gocron.Scheduler {return gocron.NewScheduler(time.Local)
}3.2 redis同步到数据库
func RelationMoveToDB() error {logger : zap.InitLogger()ctx : context.Background()keys, err : getKeys(ctx, user::*::to_user::*::w)if err ! nil {logger.Errorln(err)return err}for _, key : range keys {res, err : GetRedisHelper().Get(ctx, key).Result()vSplit : strings.Split(res, ::)_, redisAt : vSplit[0], vSplit[1]if err ! nil {logger.Errorln(err.Error())return err}// 拆分得keykSplit : strings.Split(key, ::)uid, tid : kSplit[1], kSplit[3]userID, err : strconv.ParseInt(uid, 10, 64)if err ! nil {logger.Errorln(err.Error())return err}toUserID, err : strconv.ParseInt(tid, 10, 64)if err ! nil {logger.Errorln(err.Error())return err}// 检查是否存在对应IDu, err : db.GetUserByID(ctx, userID)if err ! nil {logger.Errorln(err.Error())return err}tu, err : db.GetUserByID(ctx, toUserID)if err ! nil {logger.Errorln(err.Error())return err}if u nil || tu nil {delErr : deleteKeys(ctx, key, RelationMutex)if delErr ! nil {logger.Errorln(delErr.Error())return delErr}continue}// 查询是否存在关注记录relation, err : db.GetRelationByUserIDs(ctx, userID, toUserID)if err ! nil {logger.Errorln(err.Error())return err} else if relation nil redisAt 1 {// 数据库中没有该关注记录且最终状态为关注则插入数据库err db.CreateRelation(ctx, userID, toUserID)// 插入后删除Redis中对应记录delErr : deleteKeys(ctx, key, RelationMutex)if delErr ! nil {logger.Errorln(delErr.Error())return delErr}if err ! nil {logger.Errorln(err.Error())return err}} else if relation ! nil redisAt 2 {// 数据库中有该关注记录且最终状态为取消关注则从数据库中删除该记录err db.DelRelationByUserIDs(ctx, userID, toUserID)// 删除Redis中对应记录delErr : deleteKeys(ctx, key, RelationMutex)if delErr ! nil {logger.Errorln(delErr.Error())return delErr}if err ! nil {logger.Errorln(err.Error())return err}}// 删除Redis中对应记录delErr : deleteKeys(ctx, key, RelationMutex)if delErr ! nil {logger.Errorln(delErr.Error())return delErr}}return nil
}