当我们想要生成 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
}
运行结果
来源:编程村