日常工作总结(二)
之前写过一个go日常使用的总结文章,最近刚忙完一个活动,想再总结一下,发现归类为go有些片面,不仅仅涉及到go,而且更多的可能是代码的书写规范或者追求更好的书写方式,因此索性变成日常工作总结好了~
表设计问题:
主要针对InnoDB存储引擎,库名、表名、字段名、索引名必须使用小写字母,并且不能以MySQL关键字命名这个不需要多说,在建表时候所有的表都应该携带ctime(创建时间)和mtime(修改时间)这2个字段,便于数据分析和故障排查。时间类型,首选整型INT、INT UNSIGNED类型,其次使用timestamp类型。
if else问题:
在常规业务判断中,应优先判断条件不满足的情况,即条件不满足就优先退出,而不是顺着常规的思维,如领奖,可能需要时间在截至日期之前,然后达到领奖条件,进行领奖。可先判断时间超过截至日期直接返回,未完成直接返回,减少请求。换成代码描述如下:
//避免这种写法
if xxx {
xxxxxx
} else {
return
}
//使用这种写法,无需写else
if !xxx {
return
}
缓存问题:
需要存的都是用户态的东西,而全局的东西可以直接获取到的就不需要加入缓存中。例如我们接口需要返回一个list,里面包含了当前阶段,当前阶段是否解锁,当前阶段是否领奖。那么实际上当前阶段是否领奖是一个全局的东西,这个东西直接就可以获取到,并且每个用户都是相同的,直接判断即可,无须存入缓存中,虽然它可能只是一个0/1的数字,而是否领奖与用户相关,只存当前用户的领奖状态即可。
在redis的hashmap中,除了hget还提供了hgetall指令,可以一次性取出该key下所有的域和值,但是要注意返回的结果是个map,即field value field value…形式,在取值的时候注意下标。同时要避免循环调用hget取值,在线上环境很有可能出现请求超时的情况,如果实在要使用hget,可以采用HGET key field1 field2…这种形式。这里只对hgetall给出示例代码:
func (d *Dao) CacheXXX(c context.Context, bid int64, day string) (res []*mdl.CountXXX, err error) {
var (
bss []int64
key = keyXXX(bid, day)
conn = d.redis.Get(c)
)
defer conn.Close()
if bss ,err = redis.Int64(conn.Do("HGETALL", key)); err != nil {
log.Error("...")
return
}
for i := 1; i < len(bss); i += 2 { //注意i从1开始,且自增2
item := &mdl.CountXXX{Id: bss[i-1], Count: bss[i]}
res = append(res, item)
}
return
}
slice切片问题
切片不能直接拿值,应首先判断有没有,否则会出现index out of rang切片越界问题,或者使用for range的方式循环取值。同时在使用切片的时候,应尽量使用append方法而不是直接的赋值形式。
阶段条件判断问题
如上面领奖的场景,领奖的条件可能有用户必须先完成某些前置任务,同时总值达到不同的峰值,可以领不同的奖,这就出现多个阶段的是否满足领奖条件判断,这种情况下可以在配置中配置一个Map或切片来代表各个阶段的领奖总值条件,如:
[
{
step:1
value:1000000
},
{
step:2
value:8000000
}
]
生成一个map放到内存中,map[int]int64,然后在方法的一开始就进行是否满足条件判断
if val,ok := map[step];!ok {
err = ecode.RequestErr
return
} else {
if s.allCur < val {
err = ecode.RequestErr
return
}
}
这样既过滤了非法的参数,又将领奖总值条件统一的提前判断,从而无需在后面根据阶段分case去判断是否满足条件,也避免了总值未达到领奖条件时还需要进行用户是否完成前置任务的判断。除此之外还有一个好处,因为配置在配置文件中,可以避免后面因需求变动需要修改代码重新发版的问题。
sql请求过量503限流问题:
在很多场景,我们需要监听某些表的变化,然后进行一些操作。如我站的投币、点赞业务,这个每秒的请求量是非常大的,假如现在的需求是当用户对当前活动的视频稿件进行投币时,就完成该活动的某个任务。那么就需要监听投币的消息,消息类型中包含了当前视频稿件的id,我们需要根据这个id来查是否是活动稿件,是的话再执行完成任务操作。那么这个时候如果直接使用select去查当前的id记录是否存在,在请求量很大的时候,就会出现503的问题,直接限流。因此在请求量很大的时候,应该换个逻辑,查询数据库转为走内存,由于活动id是已知的,可以定时每10秒查询一下当前活动id有哪些稿件,使用一个map来存储,然后来一个消息比对一次,这样可以在一定程度上避免503限流的问题。
还没有评论,来说两句吧...