生产环境开发踩过的坑~

记录一些开发中踩过的坑~

2021.9.4 go mod替换指定版本

go mod edit -replace=old[@v]=new[@v]
go mod edit -replace=golang.org/x/image@v0.0.0-20180708004352-c73c2afc3b81=github.com/golang/image@v0.0.0-20180708004352-c73c2afc3b81

2021.9.1 视频封面图曝光过高
背景:
最近在做视频缩略图优化,策略是取视频前2s 60帧 png格式,对帧计算lap值,取最大的帧,magick png转jpg,将jpg作为缩略图。本地跑了400个帖子,生成新缩略图,效果很不错。
问题:
新策略封面上线后,跑了2000个视频,将新封面与老封面同放在html里对比,看效果。发现有部分新封面曝光太高、太亮。本地用转码后的视频跑了下,和老封面亮度一样,就猜想可能是因为视频转码的问题。组里其他老大也感觉没啥问题,以为曝光过高是个别问题。然后就开实验上线了。
上线后发现有很多封面曝光过高,和视频播放时的差异很大,就想办法解决这个问题。
解决:
对badcase,我本地按新策略跑了一下,发现和线上相比,选择的封面图一致,计算的lap也一致,执行的图片转码命令也一致magick xxx.png -quality xxx.jpg,本地输出的xxx.jpg没问题。我都以为上传图片的时候做了啥操作…
然后leader让我把中间生成的png文件和jpg文件先不要删,将badcase重新打入工作流,看看哪里出了问题。
最后发现现实magick图片转码后曝光高!
然后和我本地环境对比了下,2个地方不同:
1、本地:mac系统、magick 版本7.1.0
2、线上机器:linux、magick 版本7.0.6
猜想时magick版本原因,我在离线机器上升级magick到7.1.0,对同一png图片转码,果然正常了!
总结:
本次的小事故其实我有好多机会专注一下,标准点,是完全可以避免掉的。
1、新策略跑demo的时候是在本地环境跑的,没有在线上环境跑。(如果在线上跑,完全可以早点发现magick版本问题)。
2、上线后发现的曝光过高的问题,这是还没有开实验,如果这时候积极定位到问题,也可以减小影响。这个问题主要是我认为问题不大…
2021.9.1 视频封面图实验
实验是对于用户的,替换下发给用户的图片url。
1、要能对用户进行分槽。最上次收口的地方才有设备id,底层只有图片id。
2、方法提炼。

2020.03.31 不能拉取test分支合并到自己分支
只能将代码往test分支合,不能将test分支合并到自己分支,否则会污染自己分支,导致报废。应该将自己代码在本地合并到test分支,解决冲突并且在本地环境测试通过后,push到测试环境测试,最后将自己分支合并到master,可以拉去master分支到自己分支。

2020.03.31 微服务是无状态的
直播截图。
我在这块最开始的思路是直播回调接口后,开一个协程去定时访问图片url。因为直播结束后,图片url就自动失效了,所以我根据响应的状态码和响应体去结束截图的循环。
问题
如果因为网络原因导致请求失败,会出现直播正常,但是后台截图协程已经死亡。又或者主播暂时退出,也会导致截图url暂时失效。
另外要考虑服务是无状态的,单独起一个协程,当服务重启后,就不能继续截图了。
解决
在离线统计服务里,写一个函数专门定时去截取正在直播的视频图片。在回调接口里,将流id和截图url存储到数据库中。离线服务定时获取所有正在直播的直播间sid,再从数据库读取每个直播间对应截图url,拉取图片,上传到oss,sid和图片id入库。
解决后的问题:
我写了一个函数,死循环去按照上面所说的方法实现,功能确实可以实现。但是又一个问题:服务将来会部署在多个实例上,这样每个实例都会去截图。
再次解决
使用一个20秒的全局锁,每个实例的服务截图时,先获取锁,获取成功后进行一次截图。使用redis实现,设置一对键值,时长为20s。

2020.04.02 处理错误不要随便return
在离线统计服务日常数据服务里,会写一个死循环,在遇到错误时,打上日志,但是不能return!否则服务将会结束。
另外在controller处理请求时,遇到错误,也不能直接return,否则客户端将收不到响应。

2020.04.02 日志问题
日志的级别有info,debug,warn,error四个级别,Error类型的日志不能随便打印,如客户端参数错误,这个是客户端问题,不是服务端内部错误,不需要打印。因为生产环境下,一般会对error日志进行监控,不必要的错误日志会影响运维。
另外,打印日志需要打印出其上下文,方便debug,问题定位。

2020.04.10 .bash_profile启动问题
.bash_profile在终端打开时,不能自动source。
解决:
创建~/.profile文件,写入source ~/.bash_profile

2020.04.13 数据库查询语句索引问题
查询语句尽量命中索引,覆盖索引,减小数据库压力。

2020.04.13 python脚本读取mongo数据错误
1.编解码错误:读取的设备信息中存有特殊符号,需要进行utf-8编码。
2.值为null:读取的值可能为null,需要根据业务要求,设置合理的异常处理,或者过滤判断。

2020.04.13 vscode格式化代码慢
vscode自带的go格式化代码太慢,可以取消,写完项目代码后,提交版本前,使用在这里插入代码片gofmt -w src命令格式化代码,再提交上传。

2020.04.14 Go程序函数return时候报错
变量作用域的问题,在子作用域定义一个上层作用域的同名的变量。

// 直接返回,并没有返回参数,在子作用域中,并不能直接返回上一层定义作用域中返回变量
// 也就是说命名参数返回,只能返回同一级别作用域下参数,不是同一级别作用域参数需要指明返回参数值
return
// 正确返回
//return err

2020.04.14 单个接口请求的失败不要导致整个请求失败
用户打开app时,调用一个live_config接口,获取配置信息和用户权限(包括开播,观播)。在其中调用用户权限的接口,如果返回500或其他,请求失败,应该将开播,观播权限设为false,而不应该返回客户端500错误,导致之后的配置信息也没获取到。

2020.04.15 数据库操作失败不能改变返回给用户的值
用户开播权限检查,根据mid进行放量,有权限的返回true,同时入库。此时入库失败的操作打印日志即可,不能返回权限为false。

2020.04.15 数据表字段值设计
在生产环境下,一般是不能删除用户数据的,所以对于数据表应该有一个状态字段,来标记该条信息为删除状态。有时候可以把状态字段与其他字段合并,比如用户观播权限,1 有,-1 无,0 待检查。如果没有0值,会导致用户权限确定后,没办法再检测。

2020.04.29 数据表外键
某张表有外键时,可以代码生成外键id,然后修改数据的id并插入连接表,再修改当前表的外键值为id。

2020.04.29 给返回的结果加开关
在返回给客户端信息的时候,可以加一个开关。
比如直播状态linve_on=1,取拉流地址,live_on=2,取录播地址。

2020.04.29 写controller时先做参数检查

2020.05.08 服务运行起来,但是端口未绑定
问题:已经可以从kafka读取消息并写入数据库,但是发布失败,端口绑定超时,没有成功。
debug:在main函数里打印多条日志,发现kafka初始化后面的日志为打印,确定问题在kafka初始化里。看代码发现,程序卡在kafka读消息的死循环里,导致后面的端口绑定没有执行到。
解决:将kafka初始化改成协程启动。

2020.05.08 数据库查询操作尽量一次查询完成,在内存里筛选

2020.05.09 consul里配置kv
问题:Consul里配置kv,在配置api时会设置apphost和appname,为啥?
因为apphost是域名,请求服务时需要先进行域名解析。而通过appname可以在consul里做服务发现,直接请求到服务。节省一次网络开销。

2020.05.12 代码上到正式环境后也要测试
在测试环境测试成功后,合代码到master后 ,根据修改的代码,在测试一遍相关功能。注意数据库表的修改!

2020.07.10 sql问题
SELECT mid, sum(balance) as recv_diamond FROM %s WHERE mid IN %s AND currency=? AND ct>=from_unixtime(?) AND ct<from_unixtime(?) GROUP BY mid
sum记得和group by 联合使用

2020.07.11 http返回csv数据
场景: op后台需要支持运营人员的数据查询与下载
实现: 后台可以设置多种格式数据,然后修改http响应头供前端解析

fileName := fmt.Sprintf("主播数据.csv")
fileBody, err := setAnchorDataCsv(list, len(list))
if err != nil {
   
	controller.ReplyServerError(c, ctx)
	return
}

ctx.SetHeader("Content-Type", "text/csv")
ctx.SetHeader("Content-Disposition", fmt.Sprintf("attachment;filename=%s", fileName))

func setAnchorDataCsv(list []GetAnchorsDataResult, size int) (fileBody string, err error) {
   
	file := &bytes.Buffer{
   }
	w := csv.NewWriter(file)

	header := []string{
   "主播MID", "主播Coco ID", "主播昵称", "主播国家", "主播签约时间", "所属公会", "公会建立时间", "水晶收入", "开播总时长(min)", "累计有效时长(≥30min)", "累计有效天(≥2h)"}
	data := [][]string{
   
		header,
	}

	// 时间模版
	// timeLayout := "2006-01-02 15:04:05"
	for i := 0; i < size; i++ {
   
		context := []string{
   
			strconv.FormatInt(list[i].Mid, 10),
			list[i].Cid,
			list[i].Name,
			list[i].Country,
			list[i].SigningTime,
			list[i].GuildName,
			list[i].GuildFound,
			strconv.FormatInt(list[i].RecvDiamond, 10),
			strconv
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dlian丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值