本文为 2021 年 9 月知识总结。
研发编码
C / C++
无。
golang
跟时间转换有关的几个片段:
exTime := "20210901"
mytime, _ := time.Parse("20060102", exTime)
fmt.Println(mytime.UTC().Unix(), mytime.Local().Unix())
// 用本地时间格式转
mytime, _ = time.ParseInLocation("20060102", exTime, time.Local)
fmt.Println(mytime.UTC().Unix(), mytime.Local().Unix())
exTime = "2020-09-17T20:00:27"
// 时间有2个格式,这里都判断一下
mytime, _ := time.Parse("2006-01-02 15:04:05", exTime)
themonth := int(mytime.Month())
// 如果不合法,年月日均为1
if mytime.Year() == 1 && themonth == 1 && mytime.Day() == 1 {
mytime, _ = time.Parse("2006-01-02T15:04:05", exTime)
themonth = int(mytime.Month())
}
golang 转换时间时,时间模板的数值是固定的,必须为2006-01-02T15:04:05
中的对应数值,但间隔的字符可以变化,如示例中的20060102
。指定时间字符串转换为时间戳时,使用ParseInLocation
函数,指定time.Local
,否则转换出来的值会加上时区(如东八区)。
执行外部命令代码片段:
删除进程:
appname := "./httpforward_back.exe"
port := 9000
exec.Command("sh", "-c", fmt.Sprintf("pkill -SIGINT %s", appname[2:])).Output()
启动进程:
cmd := exec.Command("sh", "-c", fmt.Sprintf("%s -p %d -i \"run in port %d\" &", appname, port, port))
err := cmd.Start()
使用函数exec.Command
执行命令时,前面2个的参数为sh
和-c
,如果不使用,则会出错。删除进程的命令使用killall
也是可行的,在外网找了一些帖子,有提到用pkill -SIGINT
,所以就用了。使用Start
函数是启动进程,不会阻塞。如果要执行的命令需要返回值或等待其执行完毕,可使用Run
函数。
写文件的示例。
需求:在程序中自定义 nginx 的配置文件 nginx.conf 内容,根据参数,添加location
中不同的 URL 和对应的 端口。
知识点:由于有特殊字符,故使用反引号,阅读和处理都方便。字符串组装使用fmt.Sprintf
。调用ioutil.WriteFile
写文件。
// 定义config字符串,一些不变的内容在此
var config = `
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/opt/rh/rh-nginx116/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
server {
listen 8080 default_server;
listen [::]:8080 default_server;
server_name _;
root /opt/app-root/src;
include /opt/app-root/etc/nginx.default.d/*.conf;
location / {
}
location /foo/test9000 {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.cgi;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi.conf;
}
`
// 这是配置文件的结束符号
configend := `
}
}`
// 格式化 只针对 location 的地址和端口。
// 添加多个的话,按格式写即可
url := "test9001"
port := 9001
tmpstr := fmt.Sprintf(`
location /foo/%s {
fastcgi_pass 127.0.0.1:%d;
fastcgi_index index.cgi;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi.conf;
}
}`, url, port)
config = config + tmpstr + configend
klog.Println("write and reload nginx")
ioutil.WriteFile("/etc/nginx/nginx.conf", []byte(config), 0666)
注:上述配置内容并不完整。
Docker
在 Dockerfile 中设置环境变量:
ENV MAVEN_HOME /usr/local/apache-maven-3.8.2
ENV GOROOT /usr/local/go
ENV GOBIN /usr/local/go/bin
ENV GOPROXY https://goproxy.io,direct
# seems cant pass $MAVEN_HOME here
ENV PATH $PATH:/usr/local/apache-maven-3.8.2/bin:/usr/local/go/bin
注:在构建镜像中,观察输出日志,会将物理机的环境变量解析进来,如最后一行的 $PATH 会变为物理上的 $PATH 的具体值。如果使用 Dockerfile 定义的环境变量,似乎不生效。
Linux
zip压缩
对于相同文件/目录,不同时间点用 zip 压缩,得到的 zip 文件,md5 值会不相同(时间间隔非常短则无此现象)。使用-X -D
可解决,示例:
zip -qr -X -D c.zip hello/
参考 https://stackoverflow.com/questions/19523063/zip-utility-giving-me-different-md5sum-every-time-in-linux
编码其它
有些工程跟踪较麻烦,有些是因为条理性和逻辑性不够好,也有些是因为线索不明导致的。比如一个 C++ 类,某个业务处理示例如下:
ret = get(m_path); // 使用成员变量m_path
search_dir(m_path); // 使用成员变量m_path
mysort() // 不带参数,函数内使用了前面赋值了的成员变量m_path,同时设置了成员变量m_file
changedate(m_file) // 这里直接用m_file传参
该示例的具体处理见上面的注释,从注释看是没问题,但是,单纯从函数调用及参数,是比较难看到逻辑的,需要跟踪每个函数及对应的成员变量才能理清数据流向。
对此,个人看法是:
如果类中有工具函数的话,不要使用类成员变量。
业务函数中,能从成员变量看到主线。或加上注释。
研发知识
参考一些开源项目的 git 提交日志格式,分为“头部 正文 尾部”三部分。根据实际情况,自己整理一下。
头部: 给出本次提交的类型及影响范围。如:格式修改 测试 重构 bug修正 (影响范围)
正文: 描述本次提交的变化,可列表。
尾部:一些备注或注意事项
实际示例:
头部 bug修正(时间同步模块)
正文 时间同步模块减小时间差判断的阈值,避免波动。
尾部(附录) 关闭#1
研发思考
适当时候做适当事
当初想入门后台管理系统,选定 vue + golang 路线。查了很多资料,也下载了很多工程源码,发现学不进去。后来才发现是因为工程太复杂,并不适合新手。遂放弃,至今因其它事缘由,一直未能再动手写。
本月开始真正搞组织革新,jenkins 倒好,但 Java 只看了一点语法,工程是 springboot 的,在初期连 IDEA 工程也不懂建立,对于 jdk 那些 1.8、16等版本号也没理解。硬着头皮搞了几天才有点眉目。只感叹 IDEA 太强大了,Java 框架太多太成熟了。但就是因为太成熟了反而不喜欢研究,还是习惯 C++。
工作记录
某工程有自定义的日志函数,有操作 sqlite3 数据库,等等。在设备突然断电再启动后,sqlite3 数据库文件被损坏,经查其二进制,竟然在某个偏移量出现了部分的日志。百思不解,一直未解决。实然没招,后使用 cppcheck 和 valgrind 检查,修正一些编码错误/警告。将没有实质用处的函数删除(调用了但没产生作用)。
某工程需要兼容 32 位和 64 位,在 64 位系统中用%ld
打印 uint64_t 类型变量,正常,在 32 位系统运行则报段错误,使用%lld
打印,但在 64 位又出现警告,无奈,将 uint64_t 改为 long long 类型。幸好是在试点阶段发现,否则影响大了。
某工程连接的主备系统两个 sftp 服务器,该工程下载 xml 文件并判断哪个系统的文件版本较新即下载之。后发现同一文件的 md5 值不同,导致不断下载。经查,发现该文件在不同时间打包压缩,即使内容无变化,但压缩的 zip 文件 md5 值变化了。经查,可以通过参数保持 md5 一致。因工程是其它小组负责且用 Java 实现,未知如何修改。
某工程需下载远程服务器某个目录的文件,设置一 数组变量char remoteFile[128]
,在之前一切安好,但最近切换备份系统后,中秋节前一晚,某生产环境出现错误,无法下载,造成堵车,运维同事联系紧急处理。经查,是因为切换后,远程目录文件长度超过 128 字节了,且只超过2~3字符。试点现场采用的服务器IP比较短(如10.0.45.16
),未被发现,但有的服务器IP较长(如10.100.168.231
),刚好超过几个字符,于是失败。定位原因后,将相关的变量大小改大,解决问题。
参与了某路段开通的一些工作。初期,经工具检查发现某项数据不符合要求,与其它同事确认不影响,在试点测试时,另一服务器工具无法正常工作,数据未更新,问题在上线前2天被发现,并因此加班。
复盘后得到经验:与既定规则不符合的,多请教同事,并汇报领导(当初未坚持,也未上报);参数修改,需多方参与评估(其他同事负责的);生产环境需要有监控手段。
本月做的事及计划
抽时间完成转发工具编写和测试,研究并实现了一些负载均衡算法。
近来发现自己表达能力和思考能力下降了,计划看看非技术类的书。
其它点滴
本月首次还贷,正式开始房奴生活。个人的开支须更加节约了。