数据库、缓存一致性问题
有些业务场景,为了提高查询速度,会将结果存在缓存中,当db数据变化时,将可能出现数据不一致问题。原因有三种:
1.db读写分离,主从延迟
2.时序性
3.原子性
解决方案:
1.强一致性。分布式事务(2pc, 3pc)
2.降低并发时脏数据的概率
3.缩小不一致的时间,保证最终一致性。
有些业务场景,为了提高查询速度,会将结果存在缓存中,当db数据变化时,将可能出现数据不一致问题。原因有三种:
1.db读写分离,主从延迟
2.时序性
3.原子性
解决方案:
1.强一致性。分布式事务(2pc, 3pc)
2.降低并发时脏数据的概率
3.缩小不一致的时间,保证最终一致性。
又到年末,各团队都开始了年终述职,即绩效参考。说来惭愧,工作了四年多,总共参加了两次述职,但是效果很差,找不到关键点。
年终述职的目的,是要让领导看到你的工作成果,发现你解决问题的思维方式。所以,总结工作亮点、处理问题的细节尤为重要。
总结几点
年终述职一般只有10天左右的时间准备,在这么短的时间,靠回忆很容易遗漏一些不起眼的细节。
所以,在平时就要养成记录的习惯。我倾向于使用思维导图,用时间线或者类型分类记录。
记录内容
举个例子,
主题:创建账号生成默认密码
背景:在做进校业务中,需要在后台导入老师学生信息,创建账号,同时生成默认密码,生成规则是姓的全拼+123456
问题:找了很多提取汉字的拼音的开源包无法区分多音字,就会导致生成的密码并非是老师的姓的拼音。举个例子,有个老师姓曾,通过组件提取的拼音为【ceng】,生成的默认密码是ceng123456,影响老师使用体验。
解决方案:首先想到的是通过技术手段解决,找一个针对中国姓氏的转换包,不过调研一些开源项目后并没有找到。后来经过讨论分析,我们存储的用户名是老师的姓名全拼,这是由学校提供的,基本不会出现错误。于是,在生成默认密码时,将通过转换包生成的拼音来和老师全拼比较
if strings.HasPrefix(username, pinyin) {
return pinyin + "123456"
}
[rd@mark-k8s-log-213-235 mark]$ df -lh
文件系统 容量 已用 可用 已用% 挂载点
devtmpfs 7.8G 0 7.8G 0% /dev
tmpfs 7.8G 24K 7.8G 1% /dev/shm
tmpfs 7.8G 928K 7.8G 1% /run
tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup
/dev/vda1 50G 7.5G 40G 16% /
/dev/vdb1 394G 309G 86G 79% /data
tmpfs 1.6G 0 1.6G 0% /run/user/0
tmpfs 1.6G 0 1.6G 0% /run/user/2000
[rd@mark-k8s-log-213-235 mark]$ du -sh *
3.3M fe-mk-admin-mis
396K fe-mk-h5-student
604K fe-mk-h5-teacher
452K fe-mk-rd-toolmis
1.3M fe-mk-resource-mis
21M fe-mk-teacher-mis
34G markapi
43G mkexam
108M mk-node-export-server
7.3M mkresource
113G mkscanner
4.0G mksmartpen
106M mktag
50G mktiku
75G mktool
18M rewrite
等同于
[rd@mark-k8s-log-213-235 mark]$ du -h --max-depth=1
20M ./fe-mk-teacher-mis
592K ./fe-mk-h5-teacher
106M ./mk-node-export-server
1.3M ./fe-mk-resource-mis
72G ./mktool
3.2M ./fe-mk-admin-mis
7.4M ./mkresource
106M ./mktag
380K ./fe-mk-h5-student
113G ./mkscanner
49G ./mktiku
18M ./rewrite
33G ./markapi
4.0G ./mksmartpen
448K ./fe-mk-rd-toolmis
41G ./mkexam
309G .
unix_timestamp(now())
number, _ := strconv.Atoi(str) //number 为int类型
str := string(rune(number))
int64, err := strconv.ParseInt(string, 10, 64)
string:=strconv.FormatInt(int64,10)
git log 默认时区为UTC,显示时间比本地晚8小时
显示本地时间
git log --date=local
ES是面向文档的,文档是数据的最小单位
文档会被序列化为json格式,保存在ES中
每个文档有一个unique ID
元数据用于标注文档的相关信息
index - 索引是文档的集合
索引的settings与mapping:
区别:
# Click the Variables button, above, to create your own variables.
GET ${exampleVariable1} // _search
{
"query": {
"${exampleVariable2}": {} // match_all
}
}
GET _cat/nodes?v
//查看索引相关信息
GET kibana_sample_data_ecommerce
//查看索引的文档总数
GET kibana_sample_data_ecommerce/_count
//查看indices
GET _cat/indices/.kibana?v&s=index
//查看状态为绿的索引
GET _cat/indices?v&health=green
//按文档个数排序
GET _cat/indices?v&s=docs.count:asc
package main
import s "strings"
import "fmt"
var p = fmt.Println
func main() {
p("Contains: ", s.Contains("test", "es")) //是否包含 true
p("Count: ", s.Count("test", "t")) //字符串出现字符的次数 2
p("HasPrefix: ", s.HasPrefix("test", "te")) //判断字符串首部 true
p("HasSuffix: ", s.HasSuffix("test", "st")) //判断字符串结尾 true
p("Index: ", s.Index("test", "e")) //查询字符串位置 1
p("Join: ", s.Join([]string{"a", "b"}, "-"))//字符串数组 连接 a-b
p("Repeat: ", s.Repeat("a", 5)) //重复一个字符串 aaaaa
p("Replace: ", s.Replace("foo", "o", "0", -1)) //字符串替换 指定起始位置为小于0,则全部替换 f00
p("Replace: ", s.Replace("foo", "o", "0", 1)) //字符串替换 指定起始位置1 f0o
p("Split: ", s.Split("a-b-c-d-e", "-")) //字符串切割 [a b c d e]
p("ToLower: ", s.ToLower("TEST")) //字符串 小写转换 test
p("ToUpper: ", s.ToUpper("test")) //字符串 大写转换 TEST
p("Len: ", len("hello")) //字符串长度
p("Char:", "hello"[1]) //标取字符串中的字符,类型为byte
}
ctx.SetCookie("ZJXUSS", res.ZJXUSS, 0, "/", ctx.Request.Host, false, true)
获取cookie
cookie, err := ctx.Cookie("ZJXUSS")
结合源码了解一下http协议里的cookie:
// SetCookie adds a Set-Cookie header to the ResponseWriter's headers.
// The provided cookie must have a valid Name. Invalid cookies may be
// silently dropped.
func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) {
if path == "" {
path = "/"
}
http.SetCookie(c.Writer, &http.Cookie{
Name: name,
Value: url.QueryEscape(value),
MaxAge: maxAge,
Path: path,
Domain: domain,
SameSite: c.sameSite,
Secure: secure,
HttpOnly: httpOnly,
})
}
gin的实际是封装了go的cookie操作http.SetCookie,第二个参数传的cookie的结构:
// A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an
// HTTP response or the Cookie header of an HTTP request.
//
// See https://tools.ietf.org/html/rfc6265 for details.
type Cookie struct {
Name string
Value string
Path string // optional
Domain string // optional
Expires time.Time // optional
RawExpires string // for reading cookies only
// MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
// MaxAge>0 means Max-Age attribute present and given in seconds
MaxAge int
Secure bool
HttpOnly bool
SameSite SameSite
Raw string
Unparsed []string // Raw text of unparsed attribute-value pairs
}
name、value: 要在cookie保存的键值对
maxAge: max-age,cookie保存时间
0: 不过期
-1: 不保存
>0: 保存多少秒
domain: 域名
secure: 防止信息传输泄漏
true: 只在https中传输,http不能传输
false: 可以在https、http中传输
httpOnly: 禁止js读取,防止xss攻击
go向上取整方法 math.ceil(),该方法接收一个浮点型(float64)参数,如果小数不为0则会将小数舍去,小数点前数字加一。
如果除数和被除数都是int类型,需要手动转一下类型。
错误写法
batch := int(math.Ceil(float64(count / BATCH)))
正确写法
batch := int(math.Ceil(float64(count) / BATCH))