分布式ID生成器及redis,etcd分布式锁

分布式ID生成器及snowflake(雪花)算法实现 分布式ID的特点 全局唯一性:不能出现有重复的ID标识,这是基本要求。 递增性:确保生成ID对用户或业务都是递增的。 高可用性:确保任何时候都能生成正确的ID。 高性能性:在高并发的环境下依旧表现良好。 分布式ID生成器不仅仅用于生成用户ID,实际互联网中有很多场景都需要能够生成类似MYSQL自增ID这样不断增大,同时又不会重复的ID,以支持业务中的高并发场景。 比较经典的场景有:电商促销时短时间会有大量的订单涌入到系统,比如每秒10w+;微博热搜在短时间会产生大量的相关微博转发和评论信息。在这些业务环 阅读详情

分布式id生成器

有时我们需要能够生成类似MySQL自增ID这样不断增大,同时又不会重复的id。以支持业务中的高并发场景。比较典型的,电商促销时,短时间内会有大量的订单涌入到系统,比如每秒10w+。明星出轨时,会有大量热情的粉丝发微博以表心意,同样会在短时间内产生大量的消息。

在插入数据库之前,我们需要给这些消息、订单先打上一个ID,然后再插入到我们的数据库。对这个id的要求是希望其中能带有一些时间信息,这样即使我们后端的系统对消息进行了分库分表,也能够以时间顺序对这些消息进行排序。

Twitter的snowflake算法是这种场景下的一个典型解法。先来看看snowflake是怎么一回事:

snowflake中的比特位分布

首先确定我们的数值是64位,int64类型,被划分为四部分,不含开头的第一个bit,因为这个bit是符号位。用41位来表示收到请求时的时间戳,单位为毫秒,然后五位来表示数据中心的id,然后再五位来表示机器的实例id,最后是12位的循环自增id(到达1111,1111,1111后会归0)。

这样的机制可以支持我们在同一台机器上,同一毫秒内产生2 ^ 12 = 4096条消息。一秒共409.6万条消息。从值域上来讲完全够用了。

数据中心加上实例id共有10位,可以支持我们每数据中心部署32台机器,所有数据中心共1024台实例。

表示timestamp的41位,可以支持我们使用69年。当然,我们的时间毫秒计数不会真的从1970年开始记,那样我们的系统跑到2039/9/7 23:47:35就不能用了,所以这里的timestamp实际上只是相对于某个时间的增量,比如我们的系统上线是2018-08-01,那么我们可以把这个timestamp当作是从2018-08-01 00:00:00.000的偏移量。

worker_id分配

timestamp,datacenter_id,worker_id和sequence_id这四个字段中,timestamp和sequence_id是由程序在运行期生成的。但datacenter_id和worker_id需要我们在部署阶段就能够获取得到,并且一旦程序启动之后,就是不可更改的了(想想,如果可以随意更改,可能被不慎修改,造成最终生成的id有冲突)。

一般不同数据中心的机器,会提供对应的获取数据中心id的API,所以datacenter_id我们可以在部署阶段轻松地获取到。而worker_id是我们逻辑上给机器分配的一个id,这个要怎么办呢?比较简单的想法是由能够提供这种自增id功能的工具来支持,比如MySQL:

mysql> insert into a (ip) values("10.1.2.101");
Query OK, 1 row affected (0.00 sec)

mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)

从MySQL中获取到worker_id之后,就把这个worker_id直接持久化到本地,以避免每次上线时都需要获取新的worker_id。让单实例的worker_id可以始终保持不变。

当然,使用MySQL相当于给我们简单的id生成服务增加了一个外部依赖。依赖越多,我们的服务的可运维性就越差。

考虑到集群中即使有单个id生成服务的实例挂了,也就是损失一段时间的一部分id,所以我们也可以更简单暴力一些,把worker_id直接写在worker的配置中,上线时,由部署脚本完成worker_id字段替换。

开源实例

标准snowflake实现

github.com/bwmarrin/snowflake 是一个相当轻量化的snowflake的Go实现。其文档对各位使用的定义见图 6-2所示。

图 6-2 snowflake库

和标准的snowflake完全一致。使用上比较简单:

package main

import (
    "fmt"
    "os"

    "github.com/bwmarrin/snowflake"
)

func main() {
    n, err := snowflake.NewNode(1)
    if err != nil {
        println(err)
        os.Exit(1)
    }

    for i := 0; i < 3; i++ {
        id := n.Generate()
        fmt.Println("id", id)
        fmt.Println(
            "node: ", id.Node(),
            "step: ", id.Step(),
            "time: ", id.Time(),
            "\n",
        )
    }
}

当然,这个库也给我们留好了定制的后路,其中预留了一些可定制字段:

    // Epoch is set to the twitter snowflake epoch of Nov 04 2010 01:42:54 UTC
    // You may customize this to set a different epoch for your application.
    Epoch int64 = 1288834974657

    // Number of bits to use for Node
    // Remember, you have a total 22 bits to share between Node/Step
    NodeBits uint8 = 10

    // Number of bits to use for Step
    // Remember, you have a total 22 bits to share between Node/Step
    StepBits uint8 = 12

Epoch就是本节开头讲的起始时间,NodeBits指的是机器编号的位长,StepBits指的是自增序列的位长。

sonyflake

sonyflake是Sony公司的一个开源项目,基本思路和snowflake差不多,不过位分配上稍有不同,见图 6-3:

图 6-3 sonyflake

这里的时间只用了39个bit,但时间的单位变成了10ms,所以理论上比41位表示的时间还要久(174年)。

Sequence ID和之前的定义一致,Machine ID其实就是节点id。sonyflake与众不同的地方在于其在启动阶段的配置参数:

func NewSonyflake(st Settings) *Sonyflake

Settings数据结构如下:

type Settings struct {
    StartTime      time.Time
    MachineID      func() (uint16, error)
    CheckMachineID func(uint16) bool
}

StartTime选项和我们之前的Epoch差不多,如果不设置的话,默认是从2014-09-01 00:00:00 +0000 UTC开始。

MachineID可以由用户自定义的函数,如果用户不定义的话,会默认将本机IP的低16位作为machine id。

CheckMachineID是由用户提供的检查MachineID是否冲突的函数。这里的设计还是比较巧妙的,如果有另外的中心化存储并支持检查重复的存储,那我们就可以按照自己的想法随意定制这个检查MachineID是否冲突的逻辑。如果公司有现成的Redis集群,那么我们可以很轻松地用Redis的集合类型来检查冲突。

redis 127.0.0.1:6379> SADD base64_encoding_of_last16bits MzI0Mgo=
(integer) 1
redis 127.0.0.1:6379> SADD base64_encoding_of_last16bits MzI0Mgo=
(integer) 0

使用起来也比较简单,有一些逻辑简单的函数就略去实现了:

package main

import (
    "fmt"
    "os"
    "time"

    "github.com/sony/sonyflake"
)

func getMachineID() (uint16, error) {
    var machineID uint16
    var err error
    machineID = readMachineIDFromLocalFile()
    if machineID == 0 {
        machineID, err = generateMachineID()
        if err != nil {
            return 0, err
        }
    }

    return machineID, nil
}

func checkMachineID(machineID uint16) bool {
    saddResult, err := saddMachineIDToRedisSet()
    if err != nil || saddResult == 0 {
        return true
    }

    err := saveMachineIDToLocalFile(machineID)
    if err != nil {
        return true
    }

    return false
}

func main() {
    t, _ := time.Parse("2006-01-02", "2018-01-01")
    settings := sonyflake.Settings{
        StartTime:      t,
        MachineID:      getMachineID,
        CheckMachineID: checkMachineID,
    }

    sf := sonyflake.NewSonyflake(settings)
    id, err := sf.NextID()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    fmt.Println(id)
}

分布式锁

在单机程序并发或并行修改全局变量时,需要对修改行为加锁以创造临界区。为什么需要加锁呢?我们看看在不加锁的情况下并发计数会发生什么情况:

package main

import (
    "sync"
)

// 全局变量
var counter int

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
        defer wg.Done()
            counter++
        }()
    }

    wg.Wait()
    println(counter)
}

多次运行会得到不同的结果:

❯❯❯ go run local_lock.go
945
❯❯❯ go run local_lock.go
937
❯❯❯ go run local_lock.go
959

基于Redis的setnx

在分布式场景下,我们也需要这种“抢占”的逻辑,这时候怎么办呢?我们可以使用Redis提供的setnx命令:

package main

import (
	"fmt"
	"time"

	"github.com/go-redis/redis"
	"github.com/gofrs/uuid"
)

// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "zhy1996", // no password set
		DB:       0,         // use default DB
	})

	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}

var unlock_lua = `
if redis.call("get",KEYS[1]) == ARGV[1] then
	return redis.call("del",KEYS[1])
else
	return 0
end
`

func Lock(key, value string, expiration time.Duration) (bool, error) {
	is, err := rdb.SetNX(key, value, expiration).Result()
	if err != nil {
		return false, fmt.Errorf("redis setnx failed")
	}
	return is, nil
}

func UnLock(key, value string) (bool, error) {
	res, err := rdb.Eval(unlock_lua, []string{key}, value).Result()
	if err != nil {
		return false, err
	}
	v, ok := res.(int64)
	if !ok {
		return false, fmt.Errorf("lua script return is not int")
	}
	if v == 0 {
		return false, nil
	}
	return true, nil
}

func main() {
	err := initClient()
	if err != nil {
		fmt.Println(err)
	}

	ul, _ := uuid.NewV4()
	value := ul.String()

	for i := 0; i < 10; i++ {
		is, err := Lock("lock_1", value, time.Second)
		if err != nil {
			fmt.Println(err)
			return
		}
		fmt.Println("是否拿到锁:", is)
	}

	res, err := UnLock("lock_1", value)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("解锁:", res)
}

看看运行结果:

是否拿到锁: true
是否拿到锁: false
是否拿到锁: false
是否拿到锁: false
是否拿到锁: false
是否拿到锁: false
是否拿到锁: false
是否拿到锁: false
是否拿到锁: false
是否拿到锁: false
解锁: true

通过代码和执行结果可以看到,我们远程调用setnx实际上和单机的trylock非常相似,如果获取锁失败,那么相关的任务逻辑就不应该继续向前执行。

setnx很适合在高并发场景下,用来争抢一些“唯一”的资源。比如交易撮合系统中卖家发起订单,而多个买家会对其进行并发争抢。这种场景我们没有办法依赖具体的时间来判断先后,因为不管是用户设备的时间,还是分布式场景下的各台机器的时间,都是没有办法在合并后保证正确的时序的。哪怕是我们同一个机房的集群,不同的机器的系统时间可能也会有细微的差别。

所以,我们需要依赖于这些请求到达Redis节点的顺序来做正确的抢锁操作。如果用户的网络环境比较差,那也只能自求多福了。

基于etcd

etcd是分布式系统中,功能上与ZooKeeper类似的组件,这两年越来越火了。上面基于ZooKeeper我们实现了分布式阻塞锁,基于etcd,也可以实现类似的功能:

package main

import (
    "log"

    "github.com/zieckey/etcdsync"
)

func main() {
    m, err := etcdsync.New("/lock", 10, []string{"http://127.0.0.1:2379"})
    if m == nil || err != nil {
        log.Printf("etcdsync.New failed")
        return
    }
    err = m.Lock()
    if err != nil {
        log.Printf("etcdsync.Lock failed")
        return
    }

    log.Printf("etcdsync.Lock OK")
    log.Printf("Get the lock. Do something here.")

    err = m.Unlock()
    if err != nil {
        log.Printf("etcdsync.Unlock failed")
    } else {
        log.Printf("etcdsync.Unlock OK")
    }
}

etcd中没有像ZooKeeper那样的Sequence节点。所以其锁实现和基于ZooKeeper实现的有所不同。在上述示例代码中使用的etcdsync的Lock流程是:

  1. 先检查/lock路径下是否有值,如果有值,说明锁已经被别人抢了
  2. 如果没有值,那么写入自己的值。写入成功返回,说明加锁成功。写入时如果节点被其它节点写入过了,那么会导致加锁失败,这时候到 3
  3. watch /lock下的事件,此时陷入阻塞
  4. 当/lock路径下发生事件时,当前进程被唤醒。检查发生的事件是否是删除事件(说明锁被持有者主动unlock),或者过期事件(说明锁过期失效)。如果是的话,那么回到 1,走抢锁流程。

值得一提的是,在etcdv3的API中官方已经提供了可以直接使用的锁API,读者可以查阅etcd的文档做进一步的学习。

参考文章:《go语言高级编程》

sonyflake源码解读 网上大多数文章都只是说了snowflake或sonyflake的原理,但好像都没有多少是对源码的解读,对于初学者来说还需要多一些从别的角度去学习这个算法的思想,所以写了这篇文章,尝试从源码的角度去理解这个算法 sonyflake官方说了是受Twitter的Snowflake启发而衍生的分布式唯一ID生成算法。 目录结构 既然我们是从源码的角度去学习,那么就要先了解清楚这个包的目录结构是如何的。 能看得出来,整个包的文件数都是非常少的,非常精简 ├── awsutil │ └── aw 阅读详情

相关推荐

snoyflake 线上 panic

sonyflake 线上 panic

蜂蜜味的哈士奇 724

【记录】Golang分布式ID生成-SonyFlake

介绍 使用 核心代码 package id_generator import ( "math/rand" "sync" "time" "github.com/sony/sonyflake" ) var sf *sonyflake.Sonyflake var rg = struct { sync.Mutex rand *rand.Rand }{ rand: rand.New(rand.NewSource(time.Now().UnixNano())), }

dnice的博客 4240

C++分布式锁实现:Redis方案与工程实践详解

在分布式系统中,当多个进程或服务需要协调访问共享资源时,互斥访问机制成为核心需求。其基本原理是通过一个全局可见的协调服务,确保在任意时刻只有一个客户端能执行关键操作。这项技术的核心价值在于保障数据一致性与系统正确性,尤其在高并发场景如电商秒杀、金融交易中至关重要。常见的实现方案包括基于Redis、ZooKeeper和etcd等,它们各自在一致性模型和性能上有所权衡。其中,基于Redis的SET NX PX命令配合Lua脚本是实现分布式锁的流行方案,因其高性能和简洁性被广泛采用。在实际的C++工程实践中,需要

weixin_34253126的博客 258

Sonyflake:分布式唯一ID生成器

Sonyflake 是一个受 Twitter Snowflake 启发的分布式唯一 ID 生成器。该项目主要使用 Go 语言编写,适用于需要在分布式环境中生成唯一 ID 的场景。Sonyflake 通过将时间戳、序列号和机器 ID 组合来生成唯一的 ID,确保在多主机和多核心环境中也能保持高性能和唯一性。 ## 项目核心功能 Sonyflake 的核心功能是生成分布式环境下的唯一 ID。其生成...

gitblog_01134的博客 618

Java分布式技术面试核心:Spring Cloud与Seata实战

分布式系统是构建高并发、高可用应用的核心技术,其核心挑战在于解决数据一致性与服务协同问题。通过分布式事务框架(如Seata)和微服务架构(如Spring Cloud),开发者可以实现跨服务的原子操作。在电商、金融等场景中,分布式事务的六种解决方案(如2PC、TCC、SAGA)各有适用场景,需根据业务需求选择。Spring Cloud Alibaba生态(含Nacos、Sentinel)为微服务提供了注册中心、配置管理等基础能力,而Seata的AT模式通过全局事务管理简化了分布式事务实现。掌握这些技术不仅能应

weixin_34109408的博客 315

2026年Java面试八股文大全:核心考点与实战策略

Java面试中的技术考察往往围绕JVM、并发编程和Spring框架等核心概念展开。理解JVM内存模型、垃圾回收机制以及并发容器的设计原理,是构建稳定高效Java应用的基础。这些底层知识不仅影响系统性能,更直接关系到分布式场景下的架构设计能力。随着微服务和云原生技术的普及,对Spring生态的深度掌握成为中级开发者向高级进阶的关键门槛。本资料针对当前互联网企业的实际需求,系统梳理了从Java基础到分布式系统的知识体系,特别包含虚拟线程、响应式编程等前沿技术的面试应对策略,帮助开发者突破薪资涨幅瓶颈。

weixin_33868027的博客 334

Java面试题总结16之分布式id生成方案

Twitter开发的一种生成64位ID的服务,基于时间戳、节点ID和序列号。这种方法涉及到使用数据库来生成和管理ID段,以实现分布式ID的生成。是一个高性能的键值数据库,它可以用于生成分布式唯一标识符。分布式协调服务在集群中生成唯一ID。

weixin_51627264的博客 1489

Go实战:分布式ID生成器

分布式ID生成器的难点集中在时钟回拨和机器ID分配。回拨处理做分级,小回拨等待,大回拨报错,绝不带病生成。机器ID用etcd租约分配,崩溃自动释放,避免ID冲突。ID趋势递增对存储引擎写入性能影响巨大,随机ID会让B+树页分裂激增。生产环境务必加监控,回拨次数和生成量是两个核心指标,配合Bloom Filter做去重兜底,ID重复这类故障就能在用户感知前拦截。

白话机器学习 231

除了加锁,还能怎么办?盘点雪花算法ID重复的5种应对策略与选型建议

本文深入探讨了雪花算法在分布式高并发场景下的ID重复问题,提出了5种优化策略,包括位分配动态调整、分布式协调器方案对比和混合架构设计模式。特别针对时钟回拨、序列号耗尽等痛点,提供了Redis分布式锁之外的解决方案,帮助开发者实现高性能ID生成。

weixin_30776273的博客 395

【信息科学与工程学】计算机科学与自动化——第八十一篇 Java分布式软件高并发/高可用算法01

4. 消息队列(如Kafka的Topic分区,本质是范围)。3. 若是ACCEPT事件,bossGroup线程接受连接,创建SocketChannel,并将其注册到workerGroup的一个EventLoop的Selector上,关注READ事件。1. 分布式缓存分片(如Redis Cluster)。4. 分布式文件存储(如Ceph CRUSH)。6. 调用栈的模拟(如协程)。3. 服务网格(如Istio)的基础。2. 本地缓存与集中式缓存(如Redis)的一致性维护。3. 静态数据(如配置)缓存。

weixin_49199313的博客 1229

indigo:使用Sonyflake并由Base58编码的分布式唯一ID生成器

靛青 关于 使用Sonyflake并由Base58编码的分布式唯一ID生成器。 ID最大长度为11个字符,无符号int64最大值。 编码器可以更改您的原始编码器;) 安装 $ go get -u github.com/osamingo/indigo 用法 package main import ( "log" "sync" "time" "github.com/osamingo/indigo" ) var g * indigo. Generator func init () { t := time . Unix ( 1257894000 , 0 ) // 2009-11-10 23:00:00 UTC g = indigo . New ( nil , indigo . StartTime ( t )) _ , err := g . NextID () if err !

顺丰分布式笔试题复盘:事务、锁、缓存一致性与任务调度考点解析

分布式系统设计绕不开一致性问题,从CAP定理的取舍到BASE理论的最终一致,工程师需要在不同场景下权衡强一致与可用性。分布式事务(如Seata AT模式、本地消息表)和分布式锁(如Redis锁、ZooKeeper锁)是保障数据一致性的两大关键手段,而分布式任务调度平台则解决多节点下定时任务的重复执行与分片处理问题。这些技术共同构成了分布式开发的基石,广泛应用于电商订单、物流中转、微服务治理等场景。本文基于顺丰科技分布式开发工程师笔试题的考点复盘,从客观题中拆解分布式基础理论、事务、缓存一致性、任务调度等高频

weixin_34377919的博客 396

(一)利用Python实现数据集读取,Python基本文件操作介绍

机器学习是计算机对大量数据的分析过程,在机器学习的实际项目中,通常都需要准备数据集,数据集通常包含的数据数量是庞大的。例如,在处理计算机视觉领域的项目时,每一张图片都是一个单独的文件,为了提高模型训练的效果,图片数量通常会比较多,因此需要合理且高效的操作将所有的图片数据读取。本篇旨在介绍如何用Python对海量文件进行遍历,也是机器学习实践的第一步。.........

ZZR2631574030的博客 6356

分布式锁实战:基于Redis与Redisson的核心原理、应用场景与避坑指南

在分布式系统中,协调多节点并发访问共享资源是保障数据一致性的核心挑战。分布式锁作为一种互斥机制,其原理在于确保在任意时刻,只有一个客户端能持有锁,从而实现对共享资源的串行化操作。这一技术对于保障操作的原子性、防止数据竞争具有关键价值,广泛应用于微服务架构下的库存扣减、分布式任务调度、幂等性控制等场景。本文聚焦于当前主流且高性能的Redis实现方案,特别是通过Redisson客户端,深入剖析其在实际工程中的应用。文章结合秒杀、缓存重建等高频热词场景,提供了从环境搭建、代码实现到功能验证的完整实践路径,并针对高

weixin_34067102的博客 295

电子设计实战:用MOS管手把手搭建D触发器电路(含时序分析避坑指南)

本文详细介绍了如何使用MOS管从零开始搭建D触发器电路,重点解析了建立时间和保持时间等关键时序参数对电路稳定性的影响。通过实测波形分析和避坑指南,帮助电子工程师掌握D触发器的实际搭建技巧与优化方法,提升数字电路设计的可靠性。

x1y2z的博客 1161

28377D Bootloader

架构

a6100309120的博客 6012

单例模式在分布式系统开发中如何使用?

摘要:本文探讨了单例模式在单JVM和分布式系统中的不同实现。在单JVM环境下,介绍了饿汉式、静态内部类和双重校验锁三种经典实现方式。针对分布式系统,提出了借助外部中间件(如ZooKeeper和Redis)的解决方案,通过分布式锁和Leader选举机制实现跨JVM的单例控制。文章重点分析了ZooKeeper临时节点和Redis的NX特性在分布式单例中的应用原理及代码实现。

专注Java后端,虚心、合作、交流 1149

量子化学仿真软件:VASP_(9).磁性材料计算

在量子化学仿真软件 VASP 中,磁性材料的计算是一个复杂但重要的过程。通过正确设置磁性状态、分析磁性性质、优化计算参数以及研究磁性相变和磁动力学,可以更准确地描述和预测磁性材料的性能。希望本节的内容能够为研究磁性材料的科研人员提供有用的参考和指导。

kkchenjj的博客 1375

26年最新Java后端社招场景项目题总结!(附100w字面试题)

本文摘要: 本文系统梳理了高并发系统与分布式架构的核心技术方案。针对百万级QPS秒杀系统,提出Redis预减库存+异步扣减、分布式锁、限流策略等解决方案;在分布式文件存储方面,阐述了分片存储、一致性哈希等技术要点。同时深入探讨了数据库优化策略,包括Elasticsearch深度分页、Redis缓存一致性方案,以及分布式ID生成器对比。在微服务架构部分,详细介绍了限流熔断、分布式事务等关键设计。最后提供了系统调优方法,涵盖FullGC排查、MySQL慢查询优化等实战经验。本文可作为构建高并发分布式系统的技术参

2401_89221445的博客 723

华为OD机试双机位C卷-敌情监控 (Py/Java/C/C++/Js/Go)

华为OD机试(机考)双机位C卷 【敌情监控】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试 - 敌情监控。

qq_45776114的博客 938

使用 Prometheus 监控 Spring Boot 应用

本文介绍了使用SpringBoot+Prometheus+Grafana实现应用监控的方案。首先在SpringBoot项目中集成Micrometer和Actuator组件,通过配置暴露Prometheus监控端点。接着配置Prometheus采集应用指标数据,并通过Grafana可视化展示。具体步骤包括:1)SpringBoot集成Micrometer;2)配置Prometheus抓取应用指标;3)安装Grafana并导入SpringBoot监控模板;4)展示JVM和业务指标。该方案可以实现对SpringB

蔡定努 430

Hutool IdUtil:分布式ID生成实战,详解雪花算法与UUID应用

在分布式系统架构中,唯一标识符(ID)的生成是数据持久化的基础技术。其核心原理是为每条记录分配一个全局唯一的标识,以确保数据的一致性与可追溯性。从技术价值看,高效的ID生成方案能直接提升数据库索引性能、支持高并发场景,并保障系统的水平扩展能力。常见的应用场景包括用户注册、订单生成、会话管理及分布式链路追踪等。本文聚焦于Hutool工具库中的IdUtil组件,它集成了雪花算法、UUID等多种主流方案,提供了开箱即用的高性能ID生成能力。针对雪花算法的时间回拨和WorkerId分配等分布式环境下的典型挑战,文章

weixin_30633405的博客 280

基于知识图谱的时空事件关联推理能力培养

随着信息技术的飞速发展,大量的时空事件数据被产生和收集,如交通流量数据、气象观测数据、社交媒体上的地理定位信息等。这些数据蕴含着丰富的知识和规律,但要从中提取有价值的信息并非易事。基于知识图谱的时空事件关联推理旨在通过构建知识图谱,将时空事件数据进行整合和关联,从而实现对事件之间潜在关系的挖掘和推理。本文的目的是系统地介绍基于知识图谱的时空事件关联推理能力的培养方法,包括核心概念、算法原理、数学模型、实际应用等方面。

操作系统内核探秘的博客 750

分布式系统入门:数据分层存储与核心挑战应对指南

在构建大规模应用时,数据存储与任务协调是两大基石。其核心原理在于根据数据的访问模式(如热、温、冷)进行分层存储,将高频访问的热数据置于内存缓存以实现毫秒级响应,而将历史归档数据下沉至低成本存储,从而在保障性能的同时优化成本。这一分层策略的技术价值在于,它为系统的水平扩展提供了清晰的数据边界,使得缓存层、数据库层和存储层可以独立伸缩。在实际应用场景中,无论是电商秒杀库存还是用户会话管理,都需要结合分布式锁、最终一致性等机制来协调多节点间的并发访问与状态同步。本文聚焦于分布式系统导论,深入探讨了数据分层模型、网

weixin_30691871的博客 346

倍福CX9020(WINCE 7)控制器使用方法和操作

CX9020系列是倍福控制器中较为经济的,操作系统为Windows Embedded Compact 7(简称WINCE7或WINEC7),相对高端控制器(WINES7以上系统),操作系统古老而简洁,上位机软件的编写困难很多,本文是笔者在使用过程中摸索的流程,旨在为CX9020系列的新用户提供参考,也可供其他CE系统的控制器参考。本文中大部分截图采用倍福中国的培训文档,这是由于笔者是在流程走通后再写这篇文章,不想再恢复出厂设置走一遍截图。因笔者在写这篇文章时使用倍福控制器经验并不丰富,难免有纰漏,请读者批评

weixin_41883890的博客 4287

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

c++游戏后端开源框架学习——wukong(一、总览)

各服务职责。

weixin_40453090的博客 236

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

上一篇: thrift 介绍及其使用
下一篇: 隔离
daemon365
博客等级 码龄2年 905粉丝 70原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值