原创

分布式学习十三:实现全局唯一id命名

温馨提示:
本文最后更新于 2022年03月26日,已超过 761 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

全局唯一id

在单体服务中,我们可以通过数据库的自增id去实现唯一id命名,

但是在分布式服务中,分库分表之后,就无法直接使用自增id了,数据库只能保证当前表的id唯一,

这个时候我们就需要通过其他方式去生成全局唯一id,例如UUID

UUID


uuid通俗来讲,就是针对于 每个机器/机器的线程/当前的时间戳/伪随机数 作为生成凭据,能保证每个机器下的每个线程都会生成不同的id

生成的数据大概为一串无规律的数字/一串无规律的字符串 "2145562313212","e70f1357-f260-46ff-a32d-53a086c57ade"

生成的结果由不同的算法而发生改变,但是算法的原理依据都是如上

uuid的好处在于生成速度快,重复概率低(有可能重复,但是这辈子重复的概率接近0,可以不考虑)

缺点是生成的字符串没有明确的意义,甚至没有排序,另外就是数据过长,无法直接使用

zookeeper实现全局唯一id

通过zookeeper的有序节点类型,可以很方便的实现全局唯一id

package main

import (
   "errors"
   "fmt"
   "github.com/go-zookeeper/zk"
   "strings"
   "time"
)

func main() {
   conn, _, err := zk.Connect([]string{"127.0.0.1:10001"}, time.Second)
   if err != nil {
      panic(err)
   }
   idPath := "/app1/tableName1/id/"
   createPath(conn, idPath)
   id,err := getGlobalID(conn, idPath)
   if err!=nil {
      fmt.Printf("%v \n",err)
      return
   }
   fmt.Printf("Global ID: %s",id)
}
func getGlobalID(conn *zk.Conn, idPath string) (id string,err error) {
   id, err = conn.Create(idPath+"a_", []byte{}, zk.FlagSequence, zk.WorldACL(zk.PermAll))
   if err != nil {
      return id,errors.New(err.Error())
   }
   fmt.Printf("Global ID:%s\n", id)
   return id,nil
}

func createPath(conn *zk.Conn, path string) (err error) {
   strArr := strings.Split(path, "/")
   var node string
   for _, str := range strArr {
      if str == "" {
         continue
      }
      node = node + "/" + str
      exists, _, err := conn.Exists(node)
      if err != nil {
         return errors.New(err.Error())
      }
      if exists {
         continue
      } else {
         _, err = conn.Create(node, []byte{}, 0, zk.WorldACL(zk.PermAll))
         if err != nil {
            return errors.New(err.Error())
         }
      }
   }
   return err
}

将输出:

仙士可博客

通过zookeeper生成的id优点是 有序的,可以很清楚的了解到具体的数据值(你还可以把a_改为日期),这样还可以清楚这个id的创建时间等

缺点是zookeeper生成节点很慢(需要同步到其他集群节点),另外如果超过int最大值,则需要重新使用个新的父节点生成

正文到此结束
本文目录