原文地址 : https://cloud.tencent.com/developer/article/2017632
Go实战项目-Beego的Session、日志文件的使用和[redis][1]的选择使用
session的简单使用
go标准库里面没有实现这功能,只能靠自己实现了,哦,不,是第三方库。好在beego就自带session功能,这个之前就说过了。我们只是简单使用下,高并发场景估计还得自己来实现,单纯的靠这个框架,够呛。来看下怎么使用:
1、在调用之前就需要开启
beego.BConfig.WebConfig.Session.SessionOn = true
|
beego目前支持四种session的存储引擎 memory、file、Redis 和 MySQL
默认就是memory ,但是,你重启之后就失效了,这除了写demo可以用之外,就算是保活的进程也是很肉痛,基于之前PHP框架保存文件的处理方式,我这边也是存放文件中。
2、设置存储引擎
beego.BConfig.WebConfig.Session.SessionProvider = “file”
|
3、设置存储路径
beego.BConfig.WebConfig.Session.SessionProviderConfig = “./.tmp”
|
建议,存储的文件夹名称加上“.”,这样方便git提交的时候直接过滤,但是一般情况下,没事不要去下载,或者放在项目以外的其他路径也是可以的。这样就是永久保存了,重启依然有效。
本地日志的使用
和PHP不同,常驻内存的代码调试错误或者发现线上问题等等都是需要看日志记录的,毕竟控制台那时候咱也看不到了。靠控制台发现问题也不太现实。所以很有必要加上日志,这对于习惯于PHP开发的同学来说是个不顺手的习惯,毕竟脚本调试太简单轻松了,修改立即生效。beego的启动日志也是很简单的,直接设置就好,支持多文件,按照规则来分割,默认也会按照日期来进行分割的。
logs.SetLogger(logs.AdapterFile, {"filename":"./logs/callout.log"})
|
按照这样设置后,每天也是会有一个单独的日志,名称默认就是callout.2020-10-13.001.log,我们也可以动态更改文件夹,按照日期做,这样对于排查问题是可以提高效率的,省去了很多麻烦。多文件设置只需要把logs.AdapterFile改成logs.AdapterMultiFile,后面的基本一致,可以添加分割规则。官方文档有简单的描述,我们不深究这些,能用就好。程序员经典的几句话:又不是不能用。
redis的使用
redis,很多库都是自带连接池的,所以我们没必要自己亲自去造轮子,当然,造一遍自己的提升也是相当明显的。开始使用的时候,必须是最主流的第三方框架,redigo,引入还是照旧:”github.com/garyburd/redigo/redis”,直接导入就好。但是由于笔者公司的redis采用的是集群的方式部署的,所以,考虑到这个的使用,我别无选择的使用谷歌的亲儿子库go-redis。两个都用上吧,毕竟都是主流的两个框架
redigo的使用
直接连接
func ConnectRedis() redis.Conn { conn, _ := redis.Dial("tcp", "127.0.0.1:6379") return conn }
|
连接池连接
func ConnectRedisPool() redis.Conn { connPool := &redis.Pool{ Dial: func() (conn redis.Conn, err error) { conn, err = redis.Dial("tcp", "127.0.0.1:6379") if err != nil { return nil, err } return conn, nil }, TestOnBorrow: nil, MaxIdle: 1, MaxActive: 10, IdleTimeout: 180 * time.Second, Wait: true, MaxConnLifetime: 0, }
return connPool.Get() }
|
使用的时候记得defer 调用close()函数,正常的使用是Do的方式,举个简单的设置和获取的栗子
func (c *ProcessControllers) SetRedis() { redisPool := redisClient.ConnectRedisPool() defer redisPool.Close() _, err := redisPool.Do("SET", "wjw_key", "wjw") if err == nil { c.Data["json"] = ReturnSuccess("请求成功", nil, 0) } else { c.Data["json"] = ReturnError(-4007, err.Error()) } c.ServeJSON() }
func (c *ProcessControllers) GetRedis() { redisPool := redisClient.ConnectRedisPool() defer redisPool.Close() data, err := redis.String(redisPool.Do("GET", "wjw_key")) if err == nil { c.Data["json"] = ReturnSuccess("请求成功", data, 0) } else { c.Data["json"] = ReturnError(-4007, err.Error()) } c.ServeJSON() }
|
redigo,并不支持集群的使用,也不知道为什么这么多选择使用的,是不是也说明很多企业并没有集群或者哨兵模式?那容灾容错怎么处理的呢?是不是恰恰说明,很多公司都是实用型的,没必要整这么多的弯弯绕。
go-redis的使用
谷歌出品的,支持集群和哨兵方式等的连接。这也是比redigo更吸引的地方。
直接连接
func ConnectRedis() *redis.Client { client := redis.NewClient(&redis.Options{ Addr: "127.0.0.1:6379", Password: "", DB: 0, }) return client }
|
实际上直接连接的方式,效率很低,除了写Demo验证功能之外,实际开发应该不会想不开的用吧,大多是连接池的方式使用。
连接池连接
func ConnectRedisPool() *redis.Client { client := redis.NewClient(&redis.Options{ Addr: "127.0.0.1:6379", Password: "", DB: 0, PoolSize: 15, MinIdleConns: 10, DialTimeout: 5 * time.Second, ReadTimeout: 3 * time.Second, WriteTimeout: 3 * time.Second, PoolTimeout: 4 * time.Second,
IdleCheckFrequency: 60 * time.Second, IdleTimeout: 5 * time.Minute, MaxConnAge: 0 * time.Second,
MaxRetries: 0, MinRetryBackoff: 8 * time.Millisecond, MaxRetryBackoff: 512 * time.Millisecond, Dialer: func() (conn net.Conn, err error) { netDialer := &net.Dialer{ Timeout: 5 * time.Second, KeepAlive: 5 * time.Minute, } return netDialer.Dial("tcp", "127.0.0.1:6379") }, OnConnect: func(conn *redis.Conn) error { fmt.Printf("conn=%v\n", conn) return nil }, }) return client }
|
这些注释,可以在源码里面看得到的,都有比较详细的英文描述,稍微借助工具翻译下就知道了。重点在下面的,也是笔者使用的。
集群/哨兵模式下的连接
func ConnectRedisClusterPool() *redis.ClusterClient { client := redis.NewClusterClient(&redis.ClusterOptions{ Addrs: []string{"127.0.0.1:6379"}, Password: "", MaxRedirects: 8, PoolSize: 15, MinIdleConns: 10, DialTimeout: 5 * time.Second, ReadTimeout: 3 * time.Second, WriteTimeout: 3 * time.Second, PoolTimeout: 4 * time.Second,
IdleCheckFrequency: 60 * time.Second, IdleTimeout: 5 * time.Minute, MaxConnAge: 0 * time.Second,
MaxRetries: 0, MinRetryBackoff: 8 * time.Millisecond, MaxRetryBackoff: 512 * time.Millisecond, ReadOnly: false, RouteByLatency: false, RouteRandomly: false,
OnConnect: func(conn *redis.Conn) error { fmt.Printf("conn=%v\n", conn) return nil }, }) return client }
|
使用方式和连接池的一样,只是调用的类型换成了NewClusterClient,记住,如果是哨兵模式,换成NewSentinelClient连接就行了。
调用方式,同样直接贴出两段代码:
func (c *ProcessControllers) SetRedis() { redisPool := redisClient.ConnectRedisClusterPool() defer redisPool.Close() _, err := redisPool.Ping().Result() if err == nil { err = redisPool.Set("wjw_key", "wjw hello redis", 0).Err() if err == nil { c.Data["json"] = ReturnSuccess("请求成功", nil, 0) } else { c.Data["json"] = ReturnError(-4007, err.Error()) } } else { c.Data["json"] = ReturnError(-4007, err.Error()) } c.ServeJSON() }
func (c *ProcessControllers) GetRedis() { redisPool := redisClient.ConnectRedisClusterPool() defer redisPool.Close() _, err := redisPool.Ping().Result() if err == nil { res, err := redisPool.Get("wjw_key").Result() if err == nil { c.Data["json"] = ReturnSuccess("请求成功", res, 0) } else { c.Data["json"] = ReturnError(-4008, err.Error()) } } else { c.Data["json"] = ReturnError(-4009, err.Error()) } c.ServeJSON() }
|
不是什么难点技术,后续的使用才是考验技巧的时候。