最近工作总结(29)

2019/07/01 Work

WaitGroup 不能被拷贝传递

在主 goroutine 中 Add(delta int) 索要等待goroutine 的数量。 在每一个 goroutine 完成后 Done() 表示这一个goroutine 已经完成,当所有的 goroutine 都完成后,在主 goroutine 中 WaitGroup 返回返回。

func main(){
    var wg sync.WaitGroup
    var urls = []string{
        "http://www.golang.org/",
        "http://www.google.com/",
    }
    for _, url := range urls {
        wg.Add(1)
        go func(url string) {
            defer wg.Done()
            http.Get(url)
        }(url)
    }
    wg.Wait()
}

在Golang官网中对于WaitGroup介绍是A WaitGroup must not be copied after first use,在 WaitGroup 第一次使用后,不能被拷贝

应用示例:

func main(){
 wg := sync.WaitGroup{}
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(wg sync.WaitGroup, i int) {
            fmt.Printf("i:%d", i)
            wg.Done()
        }(wg, i)
    }
    wg.Wait()
    fmt.Println("exit")
}

运行:

i:1i:3i:2i:0i:4fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc000094018)
        /home/keke/soft/go/src/runtime/sema.go:56 +0x39
sync.(*WaitGroup).Wait(0xc000094010)
        /home/keke/soft/go/src/sync/waitgroup.go:130 +0x64
main.main()
        /home/keke/go/Test/wait.go:17 +0xab
exit status 2

它提示所有的 goroutine 都已经睡眠了,出现了死锁。这是因为 wg 给拷贝传递到了 goroutine 中,导致只有 Add 操作,其实 Done操作是在 wg 的副本执行的。

网络发包阻塞的原因

来于得到吴军《信息论40讲》: 发送方于是马上把那些包重新发送,结果原来的包还没有发完,现在又要多发很多包,网络就变得更加拥堵,最后无论是发送方还是接收方都会锁死在那里。 你有时打开一个网页,刚刚显示了头上10%的内容就再也打不开下面的内容了。你就在想,即便是网速很慢,只有56K的带宽,等待时间长一点也该传完了吧。 其实不是,因为在网络的某一处信道的容量难以满足传输率的要求后,你的计算机作为接收方很长时间没有收到某个包,就无法发出接收完成的信息,传送信息的服务器就不断重新传输那些没有得到接收确认的数据包。传输就永远无法完成了。

思考如何能够增加个人的信息带宽容量?无论是学习过程中,生活上,与人交往上等等

docker 容器服务的自动重启

  • 查看容器的重启次数: docker inspect -f “” my-container
  • 获取上一次容器重启时间: docker inspect -f “” my-container
  • 设置容器服务always自动重启: docker run –restart=always my-container-server
  • 设置容器服务自动重启策略: docker run –restart=on-failure:10 my-container-server

redis配置登入密码

配置文件redis.conf增加: requirepass 123456

redis-cli: config set requirepass 123456 这样不用重启也能增加密码,并且redis重启可以读取redis.conf中的配置内容

127.0.0.1:6379> keys *
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth 123456
OK

GOPATH 还是vendor

一个加载配置文件内容的模块包, 有两个方法使用,一个是load方法,只需要在初始的时候调用一次,将配置文件内容加载到全局变量中,另一个是getkey方法,获取对应的配置值。有两个包中用到了配置文件,一个是main,一个是另一个包。main的init方法调用了load,在main处正常获得了配置值,而在另一个包获得的是nil值。代码逻辑上没有错,最后发现了,main出调用的config模块是加载自GOPATH的,而另一个包中调用的config模块加载自vendor,由于另一个包没有调用load方法,所以全局变量中的map值是空的,所以导致了获得的配置值是nil

原因:没有从GOPATH/src进入到该项目进行build,从GOPATH/src 目录进去到该项目文件夹后,再进行build,就会都以vendor的包为加载优先了

vendor和GOPATH谁优先使用,GOPATH优先使用

如果一个包在vendor和GOPATH下面都存在那么谁会优先使用呢。 结论是:

优先使用vendor目录下面的包。 如果vendor下面没有搜索到,再搜索GOPATH下面的包。 要么完整使用vendor下面的包,要么完整使用GOPATH下面的包,不会混合使用: 假如一个函数定义再GOPATH下面的包里,而没有定义在vendor路径下的同名包里,那么调用者就会报函数未定义错误,因为调用者如果找到有vendor路径下面的包,就不会去找GOPATH下面的包了。

高效能人士的七个习惯

1、积极主动–个人愿景的原则,即采取主动,为自己过去、现在及未来的行为负责,并依据原则及价值观,(而非情绪或外在环境)来下决定,创造改变,积极面对一切;

2、以终为始–自我领导的原则,个人、团队和组织在做任何计划时,均先拟出愿景和目标,并据此塑造未来,全心投注于自己最重视的原则、价值观、关系及目标之上;

3、要事第一–自我管理的原则,即实质的创造,是你的目标、愿景、价值观及要事的组织与实践;

4、双赢思维–人际领导的原则,双赢思维是一种基于互敬、寻求互惠的思考框架与心意,鼓励我们解决问题,并协助个人找到互惠的解决办法,是一种信息、力量、认可及报酬的分享;

5、知彼解己–移情沟通的原则,当我们改变以回答的心态,而以了解对方的心态去聆听别人,便能开启真正的沟通,增进彼此关系,知彼需要仁慈心,解己需要勇气,能平衡两者,则可大幅提升沟通的效率;

6、统合综效–创造性合作的原则,统合综效是创造第三种选择,既非按照我的方式,亦非你的方式,而是第三种远胜过个人之见的办法,它是互相尊重的成果,使整体获得一加一大于二的成效。

7、不断更新–平衡的自我更新的原则,在四个基本生活方面,即生理、社会、情感、心智中,不断更新自己,这个习惯提升了其它六个习惯的实施效率。

curl cip.cc 得到服务器的外网IP地址信息

重复两次注册了 driver MySQL 会报错

panic: sql: Register called twice for driver mysql
goroutine 1 [running]:
database/sql.Register(0x14ba2ae, 0x5, 0x1549280, 0x189a258)
	/usr/local/go/src/database/sql/sql.go:51 +0x189
github.com/go-sql-driver/mysql.init.0()
	/github.com/go-sql-driver/mysql/driver.go:161 +0x5c

验证码的作用

能够在一定程度上防止循环暴力匹配,得到信息

一个错误的SQL语句可能不报错且导致全表查询

select * from person where  name = "xxx" like '%xxx%' limit 10;

快速记大小端的区别

一段连续的内存:起始地址start和结束地址end

  • 大端模式: 位权大的的进制数值在start地址开始,位权大的排列在位权小的字节之前
  • 小端模式: 位权小的的进制数值在start地址开始,位权大的排列在位权小的字节之后

Redis Cluster Config 配置例子

https://juejin.im/post/5b625b9be51d4519956759d0

主从复制功能的详细步骤可以分为7个步骤:

  • 设置主服务器的地址和端口
  • 建立套接字连接
  • 发送PING命令
  • 身份验证
  • 发送端口信息
  • 同步
  • 命令传播

全量重同步的步骤如下

  • 主节点收到从服务器的全量重同步请求时,主服务器便开始执行bgsave命令,同时用一个缓冲区记录从现在开始执行的所有写命令。
  • 当主服务器的bgsave命令执行完毕后,会将生成的RDB文件发送给从服务器。从服务器接收到RDB文件时,会将数据文件保存到硬盘,然后加载到内存中。
  • 主服务器将缓冲区所有缓存的命令发送到从服务器,从服务器接收并执行这些命令,将从服务器同步至主服务器相同的状态。 ``` info replication 可用查看集群Info

192.168.17.103:6379> slaveof 192.168.17.101 6379 OK 角色已经变成从服务器


#### config

################################# REPLICATION #################################

slaveof <主服务器ip> <主服务器端口>

slaveof

masterauth <主服务器Redis密码>

masterauth

当slave丢失master或者同步正在进行时,如果发生对slave的服务请求

yes则slave依然正常提供服务

no则slave返回client错误:”SYNC with master in progress”

slave-serve-stale-data yes

指定slave是否只读

slave-read-only yes

无硬盘复制功能

repl-diskless-sync no

无硬盘复制功能间隔时间

repl-diskless-sync-delay 5

从服务器发送PING命令给主服务器的周期

repl-ping-slave-period 10

超时时间

repl-timeout 60

是否禁用socket的NO_DELAY选项

repl-disable-tcp-nodelay no

设置主从复制容量大小,这个backlog 是一个用来在 slaves 被断开连接时存放 slave 数据的 buffer

repl-backlog-size 1mb

master 不再连接 slave时backlog的存活时间。

repl-backlog-ttl 3600

slave的优先级

slave-priority 100

未达到下面两个条件时,写操作就不会被执行

最少包含的从服务器

min-slaves-to-write 3

延迟值

min-slaves-max-lag 10

```

线上数据库操作要万分小心

在线上数据库进行写操作,这是最不合适的方式,能通过接口,脚本或管理后台操作,才是好的选择

缓存穿透、缓存雪崩、缓存击穿

缓存击穿表示恶意用户模拟请求很多缓存中不存在的数据,由于缓存中都没有,导致这些请求短时间内直接落在了数据库上,导致数据库异常。这个我们在实际项目就遇到了,有些抢购活动、秒杀活动的接口API被大量的恶意用户刷,导致短时间内数据库超时 重要的接口一定要做好限流策略,防止用户恶意刷接口,同时要降级准备,当接口中的某些服务不可用时候,进行熔断,失败快速返回机制

布隆过滤器:bloomfilter就类似于一个hash set,用于快速判某个元素是否存在于集合中,其典型的应用场景就是快速判断一个key是否存在于某容器,不存在就直接返回

缓存雪崩问题: 缓存在同一时间内大量键过期(失效),接着来的一大波请求瞬间都落在了数据库中导致连接异常

方案1、也是像解决缓存穿透一样加锁排队,实现同上;

方案2、二级缓存:建立备份缓存,缓存A和缓存B,A设置超时时间,B不设值超时时间,先从A读缓存,A没有读B,并且更新A缓存和B缓存;

方案3、设置缓存超时时间的时候加上一个随机的时间长度,比如这个缓存key的超时时间是固定的5分钟加上随机的2分钟,酱紫可从一定程度上避免雪崩问题

https 只剩下域名端口和 User-Agent,其他都加密了,连 URI 都加密了

Search

    Table of Contents