绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
golang使用雪花算法生成ID
2019-11-12 15:29:55

当我们想要生成 ID,并且这个 ID 中还要包含请求时间,服务器地址等内容时,可以使用 snowflake 算法。因为我们是使用 NGINX 作为负载均衡,但是服务器并没有编号,snowflake 算法中需要使用服务器编号,所以稍微对 snowflake 做了一点改动,将当前服务器的 ip 追加到通过 snowflake 生成的 id 后面。使用了 github.com/bwmarrin/snowflake 包。


package main

import (
	"encoding/base64"
	"errors"
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/bwmarrin/snowflake"
)

func main() {

	// Create a new Node with a Node number of 1,must be between 0 and 1023
	node, err := snowflake.NewNode(3)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Generate a snowflake ID.
	id := node.Generate()

	// Print out the ID in a few different ways.
	fmt.Printf("Int64 ID: %d\n", id)
	fmt.Printf("String ID: %s\n", id)
	fmt.Printf("Base2 ID: %s\n", id.Base2())
	fmt.Printf("Base64 ID: %s\n", id.Base64())

	// Print out the ID's timestamp
	// id.Time()返回的是毫秒,转换日期用秒
	fmt.Printf("ID Time : %d\n", id.Time())
	fmt.Printf("ID Time2 : %s\n", time.Unix(id.Time()/1000, 0).Format("2006-01-02 15:04:05"))

	// Print out the ID's node number
	fmt.Printf("ID Node : %d\n", id.Node())

	// Print out the ID's sequence number
	fmt.Printf("ID Step : %d\n", id.Step())

	// Generate and print, all in one.
	fmt.Printf("ID : %d\n", node.Generate().Int64())

	/******************如果服务器有编号,则不需要下面自己追加ip*********************/

	ip, err := ExternalIP()
	if err != nil {
		fmt.Println("get ip is failed, err:", err)
	}

	s := base64.URLEncoding.EncodeToString([]byte(id.String() + "_" + ip.String()))
	fmt.Println("encode:", s)

	d, err := ParseGenerateSessionID(s)
	if err != nil {
		fmt.Println("parse generate session id is failed, err:", err)
	}
	fmt.Println("d=", d)
}

// ExternalIP get ip of local server
func ExternalIP() (net.IP, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			continue // interface down
		}
		if iface.Flags&net.FlagLoopback != 0 {
			continue // loopback interface
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return nil, err
		}
		for _, addr := range addrs {
			ip := getIpFromAddr(addr)
			if ip == nil {
				continue
			}
			return ip, nil
		}
	}
	return nil, errors.New("are you connected to the network?")
}

func getIpFromAddr(addr net.Addr) net.IP {
	var ip net.IP
	switch v := addr.(type) {
	case *net.IPNet:
		ip = v.IP
	case *net.IPAddr:
		ip = v.IP
	}
	if ip == nil || ip.IsLoopback() {
		return nil
	}
	ip = ip.To4()
	if ip == nil {
		return nil // not an ipv4 address
	}

	return ip
}

func ParseGenerateSessionID(sid string) (string, error) {
	sessionID, err := base64.URLEncoding.DecodeString(sid)
	if err != nil {
		return "", errors.New("decode base64 session id is failed")
	}

	ids := strings.Split(string(sessionID), "_")
	if len(ids) < 2 {
		return "", errors.New("parse session id ip is failed")
	}

	sessID := ids[0]
	id, err := snowflake.ParseString(sessID)
	if err != nil {
		return "", err
	}

	return "ip:" + ids[1] + " ," + "time:" + time.Unix(id.Time()/1000, 0).Format("2006-01-02 15:04:05"), nil
}


运行结果


来源:编程村

分享好友

分享这个小栈给你的朋友们,一起进步吧。

应用开发
创建时间:2020-06-17 15:31:04
应用软件开发是指使用程序语言C#、java、 c++、vb等语言编写,主要是用于商业、生活应用的软件的开发。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 栈栈
    专家
戳我,来吐槽~