snoyflake 线上 panic

背景

在业务中由于想生成唯一的 uuid,找了很多雪花算法的库,最后看到 sonyflake 的 star 很高,评价也不错就用了这个库。

但是在本地测试的时候完全没有问题,一部署到线上就出现莫名其妙的 panic,最后定位到是 sonyflake 库的问题。

原因

sonyflake 这个库使用的是 IP 最低的 16Bit 作为机器号,但是在获取这个 IP 的时候会有一个校验,判断 IP 是否是一个私有的 IP。

func isPrivateIPv4(ip net.IP) bool {
    return ip != nil &&
       (ip[0] == 10 || ip[0] == 172 && (ip[1] >= 16 && ip[1] < 32) || ip[0] == 192 && ip[1] == 168)
}

可以看出,仅当 IP 是 10,172 开头,或者是 192.168 开头,才会返回 true。

func privateIPv4(interfaceAddrs types.InterfaceAddrs) (net.IP, error) {
    as, err := interfaceAddrs()
    if err != nil {
       return nil, err
    }

    for _, a := range as {
       ipnet, ok := a.(*net.IPNet)
       if !ok || ipnet.IP.IsLoopback() {
          continue
       }

       ip := ipnet.IP.To4()
       if isPrivateIPv4(ip) {
          return ip, nil
       }
    }
    return nil, ErrNoPrivateAddress
}

func isPrivateIPv4(ip net.IP) bool {
    return ip != nil &&
       (ip[0] == 10 || ip[0] == 172 && (ip[1] >= 16 && ip[1] < 32) || ip[0] == 192 && ip[1] == 168)
}

可以看到,在第 7 行的 for 循环中,如果 IP 都不符合上面的规范就不会返回,最终在第 18 行会返回一个 ErrNoPrivateAddress 的报错。其实报错出去也还好,至少能在初始化的时候知道有问题了去处理,但是初始化函数选择吞掉了这个报错

func NewSonyflake(st Settings) *Sonyflake {
    sf, _ := New(st)
    return sf
}

这就导致,即使有错误也不会打印任何信息,返回的 sf 是一个 nil,当你在使用 sf 的时候就会报 panic 的错误。

解决方案

好在库提供了自己设置机器号的途径,那就是在调用 NewSonyflake 的时候手动传进去一个机器号,这样他就不会再自己使用 IP 判断,而是直接用你传进去的机器号。

sonyflake.NewSonyflake(sonyflake.Settings{
    MachineID: func() (uint16, error) {
       return 0,nil
    },
})

当然我们也可以对他通过 IP 获取机器号的算法进行一些改造,去除一点小小的限制

func ipv4() (net.IP, error) {
    as, err := net.InterfaceAddrs()
    if err != nil {
       return nil, err
    }

    for _, a := range as {
       ipnet, ok := a.(*net.IPNet)
       if !ok || ipnet.IP.IsLoopback() {
          continue
       }

       v4 := ipnet.IP.To4()
       if v4 == nil {
          continue
       }
       return v4, nil
    }
    return nil, fmt.Errorf("no available ipv4")
}

这样就可以愉快的使用了。

That’s all

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值