vxe-table 4.4.5 已经发布,vue 表格解决方案
vxe-table 4.4.5 已经发布,vue 表格解决方案 此版本更新内容包括: table 修复个性化列无法重置问题 toolbar 渲染器增加 toolbarButtonClassName 渲染器增加 toolbarToolClassName 详情查看:https://gitee.com/xuliangzhan_admin/vxe-table/releases/4.4.5
GroupedIdSegmentDistributor)
share:
group:
by: year
converter:
type: to_string
to-string:
pad-start: true
char-size: 8
prefix: COSID-
year-prefix:
enabled: true
delimiter: "-"
IdConverter)易用性
converter:
type: custom
custom:
type: me.ahoo.cosid.example.redis.controller.CustomIdConverter
org.springframework.boot:spring-boot-dependencies 到 v3.1.1
CosId 旨在提供通用、灵活、高性能的分布式 ID 生成器。
SnowflakeId : 单机 TPS 性能:409W/s JMH 基准测试 , 主要解决 时钟回拨问题 、机器号分配问题 并且提供更加友好、灵活的使用体验。SegmentId: 每次获取一段 (Step) ID,来降低号段分发器的网络 IO 请求频次提升性能。
IdSegmentDistributor: 号段分发器(号段存储器)
RedisIdSegmentDistributor: 基于 Redis 的号段分发器。JdbcIdSegmentDistributor: 基于 Jdbc 的号段分发器,支持各种关系型数据库。ZookeeperIdSegmentDistributor: 基于 Zookeeper 的号段分发器。SegmentChainId(推荐):SegmentChainId (lock-free) 是对 SegmentId 的增强。性能可达到近似 AtomicLong 的 TPS 性能:12743W+/s JMH 基准测试 。
PrefetchWorker 维护安全距离 (safeDistance), 并且支持基于饥饿状态的动态 safeDistance 扩容 / 收缩。在软件系统演进过程中,随着业务规模的增长 (TPS / 存储容量),我们需要通过集群化部署来分摊计算、存储压力。 应用服务的无状态设计使其具备了伸缩性。在使用 Kubernetes 部署时我们只需要一行命令即可完成服务伸缩 (kubectl scale --replicas=5 deployment/order-service)。
但对于有状态的数据库就不那么容易了,此时数据库变成系统的性能瓶颈是显而易见的。
从微服务的角度来理解垂直拆分其实就是微服务拆分。以限界上下文来定义服务边界将大服务 / 单体应用拆分成多个自治的粒度更小的服务,因为自治性规范要求,数据库也需要进行业务拆分。 但垂直拆分后的单个微服务依然会面临 TPS / 存储容量 的挑战,所以这里我们重点讨论水平拆分的方式。
数据库分库分表方案是逻辑统一,物理分区自治的方案。其核心设计在于中间层映射方案的设计 (上图 Mapping),即分片算法的设计。 几乎所有编程语言都内置实现了散列表 (java:HashMap/csharp:Dictionary/python:dict/go:map ...)。分片算法跟散列表高度相似 (hashCode),都得通过 key/shardingValue 映射到对应的槽位 (slot)。
那么 shardingValue 从哪里来呢?CosId!!
当然还有很多分布式场景需要分布式 ID,这里不再一一列举。
t_order 这张表的 Id 时是要求全局唯一的。至于 t_order_item 生成的 ID 与 t_order 是否唯一,并不影响唯一性约束,也不会产生什么副作用。 不同业务模块间也是同理。即唯一性主要解决的是 ID 冲突问题。NexMaxId。自治性还会对可用性造成影响。NexMaxId)的可用性影响。
Availability=(365*24)/(365*24+1)=0.999885857778792≈99.99%,也就是我们通常所说对可用性 4 个 9。| 分布式 ID | 全局唯一性 | 有序性 | 吞吐量 | 稳定性(1s=1000,000us) | 自治性 | 可用性 | 适应性 | 存储空间 |
|---|---|---|---|---|---|---|---|---|
| UUID/GUID | 是 | 完全无序 | 3078638(ops/s) | P9999=0.325(us/op) | 完全自治 | 100% | 否 | 128-bit |
| SnowflakeId | 是 | 本地单调递增,全局趋势递增 (受全局时钟影响) | 4096000(ops/s) | P9999=0.244(us/op) | 依赖时钟 | 时钟回拨会导致短暂不可用 | 否 | 64-bit |
| SegmentId | 是 | 本地单调递增,全局趋势递增 (受 Step 影响) | 29506073(ops/s) | P9999=46.624(us/op) | 依赖第三方号段分发器 | 受号段分发器可用性影响 | 否 | 64-bit |
| SegmentChainId | 是 | 本地单调递增,全局趋势递增 (受 Step、安全距离影响) | 127439148(ops/s) | P9999=0.208(us/op) | 依赖第三方号段分发器 | 受号段分发器可用性影响,但因安全距离存在,预留 ID 段,所以高于 SegmentId | 是 | 64-bit |
刚刚我们已经讨论了 ID 有序性的重要性,所以我们设计 ID 算法时应该尽可能地让 ID 是单调递增的,比如像表的自增主键那样。但是很遗憾,因全局时钟、性能等分布式系统问题,我们通常只能选择局部单调递增、全局趋势递增的组合(就像我们在分布式系统中不得不的选择最终一致性那样)以获得多方面的权衡。下面我们来看一下什么是单调递增与趋势递增。
单调递增:T 表示全局绝对时点,假设有 Tn+1>Tn(绝对时间总是往前进的,这里不考虑相对论、时间机器等),那么必然有 F (Tn+1)>F (Tn),数据库自增主键就属于这一类。 另外需要特别说明的是单调递增跟连续性递增是不同的概念。 连续性递增:F(n+1)=(F(n)+step) 即下一次获取的 ID 一定等于当前 ID+Step,当 Step=1 时类似于这样一个序列:1->2->3->4->5。
扩展小知识:数据库的自增主键也不是连续性递增的,相信你一定遇到过这种情况,请思考一下数据库为什么这样设计?
趋势递增:Tn>Tn-s,那么大概率有 F (Tn)>F (Tn-s)。虽然在一段时间间隔内有乱序,但是整体趋势是递增。从上图上看,是有上升趋势的(趋势线)。
Step) 影响。UUID 最大的缺陷是随机的、无序的,当用于主键时会导致数据库的主键索引效率低下(为了维护索引树,频繁的索引中间位置插入数据,而不是追加写)。这也是 UUID 不适用于数据库主键的最为重要的原因。
SnowflakeId 使用
Long(64-bit)位分区来生成 ID 的一种分布式 ID 算法。 通用的位分配方案为:timestamp(41-bit)+machineId(10-bit)+sequence(12-bit)=63-bit。
timestamp=(1L<<41)/(1000/3600/365),约可以存储 69 年的时间戳,即可以使用的绝对时间为 EPOCH+69 年,一般我们需要自定义 EPOCH 为产品开发时间,另外还可以通过压缩其他区域的分配位数,来增加时间戳位数来延长可用时间。machineId=(1L<<10)=1024,即相同业务可以部署 1024 个副本 (在 Kubernetes 概念里没有主从副本之分,这里直接沿用 Kubernetes 的定义)。一般情况下没有必要使用这么多位,所以会根据部署规模需要重新定义。sequence=(1L<<12)*1000=4096000,即单机每秒可生成约 409W 的 ID,全局同业务集群可产生 4096000*1024=419430W=41.9亿(TPS)。从 SnowflakeId 设计上可以看出:
timestamp 在高位,单实例 SnowflakeId 是会保证时钟总是向前的(校验本机时钟回拨),所以是本机单调递增的。受全局时钟同步 / 时钟回拨影响 SnowflakeId 是全局趋势递增的。machineId 需要手动设置,实际部署时如果采用手动分配 machineId,会非常低效。在 SnowflakeId 中根据业务设计的位分配方案确定了基本上就不再有变更了,也很少需要维护。但是 machineId 总是需要配置的,而且集群中是不能重复的,否则分区原则就会被破坏而导致 ID 唯一性原则破坏,当集群规模较大时 machineId 的维护工作是非常繁琐,低效的。
有一点需要特别说明的,SnowflakeId 的 MachineId 是逻辑上的概念,而不是物理概念。 想象一下假设 MachineId 是物理上的,那么意味着一台机器拥有只能拥有一个 MachineId,那会产生什么问题呢?
目前 CosId 提供了以下五种
MachineId分配器。
machineId,一般只有在集群规模非常小的时候才有可能使用,不推荐。Kubernetes 的 StatefulSet 提供的稳定的标识 ID(HOSTNAME=service-01)作为机器号。MachineId 的上一次时间戳,用于启动时时钟回拨的检查。MachineId 的上一次时间戳,用于启动时时钟回拨的检查。MachineId 的上一次时间戳,用于启动时时钟回拨的检查。时钟回拨的致命问题是会导致 ID 重复、冲突(这一点不难理解),ID 重复显然是不能被容忍的。 在 SnowflakeId 算法中,按照 MachineId 分区 ID,我们不难理解的是不同 MachineId 是不可能产生相同 ID 的。所以我们解决的时钟回拨问题是指当前 MachineId 的时钟回拨问题,而不是所有集群节点的时钟回拨问题。
MachineId 时钟回拨问题大体可以分为俩种情况:
lastTimestamp 用于运行时时钟回拨的检查,并抛出时钟回拨异常。
ClockSyncSnowflakeId 是 SnowflakeId 的包装器,当发生时钟回拨时会使用 ClockBackwardsSynchronizer 主动等待时钟同步来重新生成 ID,提供更加友好的使用体验。lastTimestamp 是无法存储在进程内存中的。当获取的外部存储的机器状态大于当前时钟时钟时,会使用 ClockBackwardsSynchronizer 主动同步时钟。
MachineState(机器号、最近一次时间戳)。因为使用的是本地文件所以只有当实例的部署环境是稳定的,LocalMachineStateStorage 才适用。MachineState 存储在 Redis 分布式缓存中,这样可以保证总是可以获取到上次服务实例停机时机器状态。JavaScript 的 Number.MAX_SAFE_INTEGER 只有 53-bit,如果直接将 63 位的 SnowflakeId 返回给前端,那么会产生值溢出的情况(所以这里我们应该知道后端传给前端的 long 值溢出问题,迟早会出现,只不过 SnowflakeId 出现得更快而已)。 很显然溢出是不能被接受的,一般可以使用以下俩种处理方案:
SnowflakeId 转换为 String 类型。
long 转换成 String。SnowflakeFriendlyId 将 SnowflakeId 转换成比较友好的字符串表示:{timestamp}-{machineId}-{sequence} -> 20210623131730192-1-0SnowflakeId 位分配来缩短 SnowflakeId 的位数(53-bit)使 ID 提供给前端时不溢出
SafeJavaScriptSnowflakeId(JavaScript 安全的 SnowflakeId)从上面的设计图中,不难看出号段模式基本设计思路是通过每次获取一定长度(Step)的可用 ID(Id 段 / 号段),来降低网络 IO 请求次数,提升性能。
NextMaxId 需要进行网络 IO 请求,此时的性能会比较低。NextMaxId,一定比上一次大,意味着下一次的号段一定比上一次大,所以从单实例上来看是单调递增的。Step 越小,乱序程度越小。当 Step=1 时,将无限接近单调递增。需要注意的是这里是无限接近而非等于单调递增,具体原因你可以思考一下这样一个场景:
ID=1,T2 时刻给 Instance 2 分发了 ID=2。因为机器性能、网络等原因,Instance 2 网络 IO 写请求先于 Instance 1 到达。那么这个时候对于数据库来说,ID 依然是乱序的。分布式 ID (CosId) 之号段链模式性能 (1.2 亿 /s) 解析
SegmentChainId 是 SegmentId 增强版,相比于 SegmentId 有以下优势:
NextMaxId 的获取导致的(会产生网络 IO)。
NextMaxId 获取,性能可达到近似 AtomicLong 的 TPS 性能:12743W+/s JMH 基准测试 。Step 大小。集群规模是我们不能控制的,但是 Step 是可以调节的。
Step 应该近可能小才能使得 ID 单调递增的可能性增大。Step 太小会影响吞吐量,那么我们如何合理设置 Step 呢?答案是我们无法准确预估所有时点的吞吐量需求,那么最好的办法是吞吐量需求高时,Step 自动增大,吞吐量低时 Step 自动收缩。Kotlin DSL
implementation("me.ahoo.cosid:cosid-mybatis:${cosidVersion}")
public class Order { @CosId(value = "order") private Long orderId; private Long userId; public Long getOrderId() { return orderId; } public void setOrderId(Long orderId) { this.orderId = orderId; } public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } }
CosIdKeyGenerateAlgorithm、CosIdModShardingAlgorithm、CosIdIntervalShardingAlgorithm已合并至 ShardingSphere 官方,未来 cosid-shardingsphere 模块的维护可能会以官方为主。
Kotlin DSL
implementation("me.ahoo.cosid:cosid-shardingsphere:${cosidVersion}")
spring: shardingsphere: rules: sharding: key-generators: cosid: type: COSID props: id-name: __share__
Long/LocalDateTime/DATE/ String / SnowflakeId),而官方实现是先转换成字符串再转换成 LocalDateTime,转换成功率受时间格式化字符影响。org.apache.shardingsphere.sharding.algorithm.sharding.datetime.IntervalShardingAlgorithm 性能高出 1200~4000 倍。| PreciseShardingValue | RangeShardingValue |
|---|---|
![]() |
![]() |
spring: shardingsphere: rules: sharding: sharding-algorithms: alg-name: type: COSID_INTERVAL_{type_suffix} props: logic-name-prefix: logic-name-prefix id-name: cosid-name datetime-lower: 2021-12-08 22:00:00 datetime-upper: 2022-12-01 00:00:00 sharding-suffix-pattern: yyyyMM datetime-interval-unit: MONTHS datetime-interval-amount: 1
org.apache.shardingsphere.sharding.algorithm.sharding.mod.ModShardingAlgorithm 性能高出 1200~4000 倍。并且稳定性更高,不会出现严重的性能退化。| PreciseShardingValue | RangeShardingValue |
|---|---|
![]() |
![]() |
spring: shardingsphere: rules: sharding: sharding-algorithms: alg-name: type: COSID_MOD props: mod: 4 logic-name-prefix: t_table_
百分位数 ,统计学术语,若将一组数据从小到大排序,并计算相应的累计百分点,则某百分点所对应数据的值,就称为这百分点的百分位数,以 Pk 表示第 k 百分位数。百分位数是用来比较个体在群体中的相对地位量数。
微信关注我们
转载内容版权归作者及来源网站所有!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。
Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。
Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。
Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。