首页 文章 精选 留言 我的

精选列表

搜索[加密工具],共10000篇文章
优秀的个人博客,低调大师

RubyMine 2021.1.3 发布,流行的 Ruby 开发工具

RubyMine 2021.1.3 现已发布,本次更新包括一些新功能和错误修复。 主要更新内容 修复了 Ruby heredoc 中语法高亮显示的问题 修复了 Rubocop 返回错误的问题 修复了几个 UI 冻结背后的问题 修复了无限索引问题 修复了 Ctrl+Shift+箭头键对文本选择的作用 修复了在快速文档中尝试显示 jpg、png 和 svg 图像时发生的错误 IDE 不再显示来自禁用插件的更新通知 修复了 “与分支比较” 对话框意外关闭的问题 修复了动态插件卸载和加载后丢失设置的问题 不再设置临时配置限制 ComponentPopupBuilder#adText 不再显示 IDE在启动时重置 Windows 文件管理器的最近文件列表 详情请查看更新公告。

优秀的个人博客,低调大师

性能工具之Jmeter压测Thrift RPC服务

2 --> 概述 Thrift是一个可互操作和可伸缩服务的框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 等等编程语言间无缝结合的、高效的服务。 Thrift最初由facebook开发,07年四月开放源码,08年5月进入apache孵化器。thrift允许你定义一个简单的定义文件中的数据类型和服务接口(IDL)。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。 其传输数据采用二进制格式,相对于XML和JSON等序列化方式体积更小,对于高并发、大数据量和多语言的环境更有优势。 Thrift它含有三个主要的组件:protocol,transport和server,其中,protocol定义了消息是怎样序列化的,transport定义了消息是怎样在客户端和服务器端之间通信的,server用于从transport接收序列化的消息,根据protocol反序列化之,调用用户定义的消息处理器,并序列化消息处理器的响应,然后再将它们写回transport。 官网地址:thrift.apache.org 基本概念 架构图 堆栈的顶部是从Thrift定义文件生成的代码。Thrift 服务生成的客户端和处理器代码。这些由图中的棕色框表示。红色框为发送的数据结构(内置类型除外)也会生成代码。协议和传输是Thrift运行时库的一部分。因此使用Thrift可以定义服务,并且可以自由更改协议和传输,而无需重新生成代码。 Thrift还包括一个服务器基础结构,用于将协议和传输绑定在一起。有可用的阻塞,非阻塞,单线程和多线程服务器。 堆栈的“底层I / O”部分根据所开发语言而有所不同。对于Java和Python网络I / O,Thrift库利用内置库,而C ++实现使用自己的自定义实现。 数据类型: 基本类型: bool:布尔值,true 或 false,对应 Java 的 boolean byte:8 位有符号整数,对应 Java 的 byte i16:16 位有符号整数,对应 Java 的 short i32:32 位有符号整数,对应 Java 的 int i64:64 位有符号整数,对应 Java 的 long double:64 位浮点数,对应 Java 的 double string:未知编码文本或二进制字符串,对应 Java 的 String 结构体类型: struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean 集合类型: list:对应 Java 的 ArrayList set:对应 Java 的 HashSet map:对应 Java 的 HashMap 异常类型: exception:对应 Java 的 Exception 服务类型: service:对应服务的类 数据传输层Transport TSocket —— 使用阻塞式 I/O 进行传输,是最常见的模式 TFramedTransport —— 使用非阻塞方式,按块的大小进行传输,类似于 Java 中的 NIO,若使用 TFramedTransport 传输层,其服务器必须修改为非阻塞的服务类型 TNonblockingTransport —— 使用非阻塞方式,用于构建异步客户端 数据传输协议Protocol Thrift 可以让用户选择客户端与服务端之间传输通信协议的类别,在传输协议上总体划分为文本 (text) 和二进制 (binary) 传输协议,为节约带宽,提高传输效率,一般情况下使用二进制类型的传输协议为多数,有时还会使用基于文本类型的协议,这需要根据项目 / 产品中的实际需求。 常用协议有以下几种: TBinaryProtocol : 二进制格式. TCompactProtocol : 高效率的、密集的二进制压缩格式 TJSONProtocol : JSON格式 TSimpleJSONProtocol : 提供JSON只写协议, 生成的文件很容易通过脚本语言解析 注意:客户端和服务端的协议要一致。 服务器类型Server TSimpleServer ——单线程服务器端使用标准的阻塞式 I/O,一般用于测试。 TThreadPoolServer —— 多线程服务器端使用标准的阻塞式 I/O,预先创建一组线程处理请求。 TNonblockingServer —— 多线程服务器端使用非阻塞式 I/O,服务端和客户端需要指定 TFramedTransport 数据传输的方式。 THsHaServer —— 半同步半异步的服务端模型,需要指定为: TFramedTransport 数据传输的方式。它使用一个单独的线程来处理网络I/O,一个独立的worker线程池来处理消息。这样,只要有空闲的worker线程,消息就会被立即处理,因此多条消息能被并行处理。 TThreadedSelectorServer —— TThreadedSelectorServer允许你用多个线程来处理网络I/O。它维护了两个线程池,一个用来处理网络I/O,另一个用来进行请求的处理。当网络I/O是瓶颈的时候,TThreadedSelectorServer比THsHaServer的表现要好。 实现逻辑 服务端 实现服务处理接口impl 创建TProcessor 创建TServerTransport 创建TProtocol 创建TServer 启动Server 客户端 创建Transport 创建TProtocol 基于TTransport和TProtocol创建 Client 调用Client的相应方法 ThriftServerDemo实例 新建Maven项目,并且添加thrift依赖包 <dependencies> <dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId> <version>0.9.3</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.7</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf-8</encoding> </configuration> </plugin> </plugins> </build> 编写IDL接口并生成接口文件 namespace java thrift.service // 计算类型 - 仅限整数四则运算 enum ComputeType { ADD = 0; SUB = 1; MUL = 2; DIV = 3; } // 服务请求 struct ComputeRequest { 1:required i64 x; 2:required i64 y; 3:required ComputeType computeType; } // 服务响应 struct ComputeResponse { 1:required i32 errorNo; 2:optional string errorMsg; 3:required i64 computeRet; } service ComputeServer { ComputeResponse getComputeResult(1:ComputeRequest request); } 执行编译命令: thrift-0.11.0.exe -r -gen java computeServer.thrift 拷贝生成的Service类文件到IDEA 服务端接口实现 public class ThriftTestImpl implements ComputeServer.Iface { private static final Logger logger = LogManager.getLogger(ThriftTestImpl.class); public ComputeResponse getComputeResult(ComputeRequest request) { ComputeType computeType = request.getComputeType(); long x = request.getX(); long y = request.getY(); logger.info("get compute result begin. [x:{}] [y:{}] [type:{}]", x, y, computeType.toString()); long begin = System.currentTimeMillis(); ComputeResponse response = new ComputeResponse(); response.setErrorNo(0); try { long ret; if (computeType == ComputeType.ADD) { ret = add(x, y); response.setComputeRet(ret); } else if (computeType == ComputeType.SUB) { ret = sub(x, y); response.setComputeRet(ret); } else if (computeType == ComputeType.MUL) { ret = mul(x, y); response.setComputeRet(ret); } else { ret = div(x, y); response.setComputeRet(ret); } } catch (Exception e) { response.setErrorNo(1001); response.setErrorMsg(e.getMessage()); logger.error("exception:", e); } long end = System.currentTimeMillis(); logger.info("get compute result end. [errno:{}] cost:[{}ms]", response.getErrorNo(), (end - begin)); return response; } private long add(long x, long y) { return x + y; } private long sub(long x, long y) { return x - y; } private long mul(long x, long y) { return x * y; } private long div(long x, long y) { return x / y; } } 服务端实现 public class ServerMain { private static final Logger logger = LogManager.getLogger(ServerMain.class); public static void main(String[] args) { try { //实现服务处理接口impl ThriftTestImpl workImpl = new ThriftTestImpl(); //创建TProcessor TProcessor tProcessor = new ComputeServer.Processor<ComputeServer.Iface>(workImpl); //创建TServerTransport,非阻塞式 I/O,服务端和客户端需要指定 TFramedTransport 数据传输的方式 final TNonblockingServerTransport transport = new TNonblockingServerSocket(9999); //创建TProtocol TThreadedSelectorServer.Args ttpsArgs = new TThreadedSelectorServer.Args(transport); ttpsArgs.transportFactory(new TFramedTransport.Factory()); //二进制格式反序列化 ttpsArgs.protocolFactory(new TBinaryProtocol.Factory()); ttpsArgs.processor(tProcessor); ttpsArgs.selectorThreads(16); ttpsArgs.workerThreads(32); logger.info("compute service server on port :" + 9999); //创建TServer TServer server = new TThreadedSelectorServer(ttpsArgs); //启动Server server.serve(); } catch (Exception e) { logger.error(e); } } } 服务端整体代码结构 log4j2.xml配置文件 <?xml version="1.0" encoding="UTF-8"?> <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出--> <!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数--> <configuration status="INFO" monitorInterval="30"> <!--先定义所有的appender--> <appenders> <!--这个输出控制台的配置--> <console name="Console" target="SYSTEM_OUT"> <!--输出日志的格式--> <PatternLayout pattern="%highlight{[ %p ] [%-d{yyyy-MM-dd HH:mm:ss}] [%l] %m%n}"/> </console> <RollingFile name="RollingFileInfo" fileName="log/log.log" filePattern="log/log.log.%d{yyyy-MM-dd}"> <!-- 只接受level=INFO以上的日志 --> <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="[ %p ] [%-d{yyyy-MM-dd HH:mm:ss}] [ LOGID:%X{logid} ] [%l] %m%n"/> <Policies> <TimeBasedTriggeringPolicy modulate="true" interval="1"/> <SizeBasedTriggeringPolicy/> </Policies> </RollingFile> <RollingFile name="RollingFileError" fileName="log/error.log" filePattern="log/error.log.%d{yyyy-MM-dd}"> <!-- 只接受level=WARN以上的日志 --> <Filters> <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY" /> </Filters> <PatternLayout pattern="[ %p ] %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] [%l] %m%n"/> <Policies> <TimeBasedTriggeringPolicy modulate="true" interval="1"/> <SizeBasedTriggeringPolicy/> </Policies> </RollingFile> </appenders> <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效--> <loggers> <!--过滤掉spring和mybatis的一些无用的DEBUG信息--> <logger name="org.springframework" level="INFO"></logger> <logger name="org.mybatis" level="INFO"></logger> <root level="all"> <appender-ref ref="Console"/> <appender-ref ref="RollingFileInfo"/> <appender-ref ref="RollingFileError"/> </root> </loggers> </configuration> Jmeter测试类编写 利用JMeter调用Java测试类去调用对应的后台服务,并记住每次调用并获取反馈值的RT,ERR%,只需要按照单线程的方式去实现测试业务,也无需添加各种埋点收集数据 新建一个JavaMaven工程,添加JMeter及thrift依赖包 <dependencies> <dependency> <groupId>org.apache.jmeter</groupId> <artifactId>ApacheJMeter_core</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>org.apache.jmeter</groupId> <artifactId>ApacheJMeter_java</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId> <version>0.11.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.11.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.11.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf-8</encoding> </configuration> </plugin> </plugins> </build> ThriftClient测试类编写 public class ThriftClient { private ComputeServer.Client client = null; private TTransport tTransport = null; public ThriftClient(String ip,int port){ try { TTransport tTransport = new TFramedTransport(new TSocket(ip,port)); tTransport.open(); TProtocol tProtocol = new TBinaryProtocol(tTransport); client = new ComputeServer.Client(tProtocol); } catch (TTransportException e) { e.printStackTrace(); } } public ComputeResponse getResponse(ComputeRequest request){ try { ComputeResponse response = client.getComputeResult(request); return response; } catch (TException e) { e.printStackTrace(); return null; } } public void close(){ if (tTransport != null && tTransport.isOpen()){ tTransport.close(); } } } 注意:需要把编写IDL接口文件拷贝到工程里 新建一个JavaClass,如下例中的TestThriftByJmeter,并继承AbstractJavaSamplerClient。AbstractJavaSamplerClient中默认实现了四个可以覆盖的方法,分别是getDefaultParameters(),setupTest(),runTest()和teardownTest()方法。 getDefaultParameters方法主要用于设置传入界面的参数; setupTest方法为初始化方法,用于初始化性能测试时的每个线程; runTest方法为性能测试时的线程运行体; teardownTest方法为测试结束方法,用于结束性能测试中的每个线程。 编写TestThriftByJmeter测试类 public class TestThriftByJmeter extends AbstractJavaSamplerClient { private ThriftClient client; private ComputeRequest request; private ComputeResponse response; //设置传入界面的参数 @Override public Arguments getDefaultParameters(){ Arguments arguments = new Arguments(); arguments.addArgument("ip","172.16.14.251"); arguments.addArgument("port","9999"); arguments.addArgument("X","0"); arguments.addArgument("Y","0"); arguments.addArgument("type","0"); return arguments; } //初始化方法 @Override public void setupTest(JavaSamplerContext context){ //获取Jmeter中设置的参数 String ip = context.getParameter("ip"); int port = context.getIntParameter("port"); int x = context.getIntParameter("X"); int y = context.getIntParameter("Y"); ComputeType type = ComputeType.findByValue(context.getIntParameter("type")); //创建客户端 client = new ThriftClient(ip,port); //设置request请求 request = new ComputeRequest(x,y,type); super.setupTest(context); } //性能测试线程运行体 @Override public SampleResult runTest(JavaSamplerContext context) { SampleResult result = new SampleResult(); //开始统计响应时间标记 result.sampleStart(); try { long begin = System.currentTimeMillis(); response = client.getResponse(request); long cost = (System.currentTimeMillis() - begin); //打印时间戳差值。Java请求响应时间 System.out.println(response.toString()+" 总计花费:["+cost+"ms]"); if (response == null){ //设置测试结果为fasle result.setSuccessful(false); return result; } if (response.getErrorNo() == 0){ //设置测试结果为true result.setSuccessful(true); }else{ result.setSuccessful(false); result.setResponseMessage("ERROR"); } }catch (Exception e){ result.setSuccessful(false); result.setResponseMessage("ERROR"); e.printStackTrace(); }finally { //结束统计响应时间标记 result.sampleEnd(); } return result; } //测试结束方法 public void tearDownTest(JavaSamplerContext context) { if (client != null) { client.close(); } super.teardownTest(context); } } 特别说明: result.setSamplerLabel("7D"); //设置java Sampler的标题 result.setResponseOK(); //设置响应成功 result.setResponseData(); //设置响应内容 编写测试Run Main方法 public class RunMain { public static void main(String[] args) { Arguments arguments = new Arguments(); arguments.addArgument("ip","172.16.14.251"); arguments.addArgument("port","9999"); arguments.addArgument("X","1"); arguments.addArgument("Y","3"); arguments.addArgument("type","0"); JavaSamplerContext context = new JavaSamplerContext(arguments); TestThriftByJmeter jmeter = new TestThriftByJmeter(); jmeter.setupTest(context); jmeter.runTest(context); jmeter.tearDownTest(context); } } 测试结果通过 使用mvn cleanpackage打包测试代码 使用mvn dependency:copy-dependencies-DoutputDirectory=lib复制所依赖的jar包都会到项目下的lib目录下 复制测试代码jar包到jmeter\lib\ext目录下,复制依赖包到jmeter\lib目录下 这里有两点需要注意: 如果你的jar依赖了其他第三方jar,需要将其一起放到lib/ext下,否则会出现ClassNotFound错误 如果在将jar放入lib/ext后,你还是无法找到你编写的类,且此时你是开着JMeter的,则需要重启一下JMeter 打开Jmeter,在添加Java请求时,注意要选择Jmeter测试类,下面的列表中可以看到参数和默认值。 下面我们将进行性能压测,设置线程组,设置10个并发线程。 服务端日志:

优秀的个人博客,低调大师

Keka 1.2.14 发布,macOS 解压缩工具

Keka 是一个 macOS 端的应用程序,可以快速创建具有高压缩率的压缩文件,支持创建 7z、ISO、DMG、TAR、ZIP 和 Bzip2 等类型的文件格式。 与此同时,Keka 还支持从多种类型的文件中解压缩文件,例如 RAR、7z、Lzma、xz、ZIP、TAR、CAB、PAX、ACE、ISO、Bzip 或 Gzip。 近日,Keka 更新至 1.2.14 版本,本次更新的内容如下: 使用剪贴板字符串设置自定义名称的选项#823 增加隐藏选项 "CalculateMD5" 来导出MD5 可以选择在提取时排除分叉和隐藏的 Mac 文件#839 简体中文翻译已更新#830 意大利语翻译已更新#831#840 法语翻译已更新#833#841 繁体中文翻译已更新#836#843 越南语翻译已更新#834 英式英语翻译已更新#838 更多详情可查看:https://github.com/aonez/Keka/releases/tag/v1.2.14

优秀的个人博客,低调大师

RubyMine 2021.1.1 发布,流行的 Ruby 开发工具

RubyMine 2021.1.1 现已发布,本次更新包括一些新功能和错误修。 新功能 添加了受信任项目的概念 重新设计了 Minitest 支持。如果用户在 RubyMine 中使用 Minitest,请更新项目配置以使用新功能。在 Minitest 配置文件 /test/test_helper.rb 中,用 Minitest::Reporters.use! 替换 MiniTest::Reporters.use! ,除非 ENV['RM_INFO'] 当使用 "收集日志和诊断数据" 行为时,收集 "jbr_err" 文件 错误修复 修复了搜索功能的问题 修复了用于自动补全的 Tab 键的问题 改进了 YARD 标签的自动补全功能 修复了在 .erb 和 .slim 之间切换时的 ClassCastException 修复了使用自定义 WSL 时 RM 无法加载已安装的 gem 的问题 修复了 xmlns 模式声明中的 “HTTP链接不安全” 检查 详细内容请查看更新公告。

优秀的个人博客,低调大师

RubyMine 2020.3.4 发布,流行的 Ruby 开发工具

RubyMine 2020.3.4 现已发布,本次更新包括一些新功能和错误修复。 新功能 添加了受信任项目的概念 重新设定了 Minitest 支持,如果你在 RubyMine 中使用 Minitest,请更新你的项目配置以使用新的功能。在你的 Minitest 配置文件 /test/test_helper.rb 中,用 Minitest::Reporters.use! 替换 MiniTest::Reporters.use! ,除非 ENV['RM_INFO'] 支持新的 Dart 语法:通用类型别名 错误修复 重做的 Minitest 支持解决了一些与运行 Minitest 测试有关的问题 修复了 “Find Usages” 不适用于 Cucumber测试的问题 修复了测试树视图中失败的测试列表在测试运行过程中会发生变化的问题 修复了IntelliJ Minitest 支持的当前实现与 MiniTest :: Reporters 冲突的问题 修复了无法删除模块的问题 详情请查看更新公告。

优秀的个人博客,低调大师

雪花算法中超级好用的ID生成工具

雪花算法里最好用的主键ID生成器 为什么用雪花ID? ❄ 因为大厂都在用,推特、百度、美团、滴滴等等。 ❄ 雪花ID是走向分布式架构的垫脚石,如果只会Guid和数据库自增,怎敢说会分布式系统架构。 ❄ 雪花ID适合小项目、大项目、超级大项目。 💎 本算法介绍 ❄ 这是一个优化的雪花算法(雪花漂移),生成的ID更短、速度更快。 ❄ 原生支持 C#/Java/Go/Rust/C 等语言,并提供 PHP、Python、Node.js、Ruby 等语言多线程安全调用库(FFI)。 ❄ 支持 k8s 等容器环境自动扩容(自动注册 WorkerId)。 ❄ 可在单机或分布式环境中生成唯一ID。 ❄ 这是计算机历史上最全面的雪花ID生成器,未来会超越自己。(目前还未发现更好的,或许你可以😀) 需求来源 💧 作为架构设计的你,想要解决数据库主键唯一的问题,特别是在分布式系统多数据库的时候。 💧 你希望这个主键是用最少的存储空间,索引速度更快,Select、Insert 和 Update 更迅速。 💧 你要考虑在分库分表(合库合表)时,主键值可直接使用,并能反映业务时序。 💧 如果这样的主键值太长,超过前端 js Number 类型最大值,须把 Long 型转换为 String 型,你会觉得有点沮丧。 💧 尽管 Guid 能自增,但占用空间大,索引速度慢,你也不想用它。 💧 应用实例可能超过50个,每个并发请求可达10W/s。 💧 在容器环境部署应用(水平扩展、自动扩容)。 💧 不想依赖 redis 的自增操作。 💧 你希望系统运行 100 年以上。 传统算法问题 ❌ 生成的ID太长。 ❌ 瞬时并发量不够。 ❌ 不能解决时间回拨问题。 ❌ 不支持后补生成前序ID。 ❌ 可能依赖外部存储系统。 新算法特点 ✔ 整形数字,随时间单调递增(不一定连续),长度更短,用50年都不会超过 js Number类型最大值。(默认配置) ✔ 速度更快,是传统雪花算法的2-5倍,0.1秒可生成50万个(基于8代低压i7)。 ✔ 支持时间回拨处理。比如服务器时间回拨1秒,本算法能自动适应生成临界时间的唯一ID。 ✔ 支持手工插入新ID。当业务需要在历史时间生成新ID时,用本算法的预留位能生成5000个每秒。 ✔ 不依赖任何外部缓存和数据库。(k8s环境下自动注册 WorkerId 的动态库依赖 redis) ✔ 基础功能,开箱即用,无需配置文件、数据库连接等。 性能数据 (参数:10位自增序列,1000次漂移最大值) 连续请求量 5K 5W 50W 传统雪花算法 0.0045s 0.053s 0.556s 雪花漂移算法 0.0015s 0.012s 0.113s 💍 极致性能:500W/s~3000W/s。(所有测试数据均基于8代低压i7计算) 如何处理时间回拨 🔶 当发生系统时间回拨时,算法采用过去时序的预留序数生成新的ID。 🔶 回拨生成的ID序号,默认靠前,也可以调整为靠后。 🔶 允许时间回拨至本算法预设基数(参数可调)。 💎 ID组成 本算法生成的ID由3部分组成(沿用雪花算法定义): +-------------------------+--------------+----------+ | 1.相对基础时间的时间差 | 2.WorkerId | 3.序列数 | +-------------------------+--------------+----------+ 第1部分,时间差,是生成ID时的系统时间减去 BaseTime 的总时间差(毫秒单位)。 第2部分,WorkerId,是区分不同机器或不同应用的唯一ID,最大值由 WorkerIdBitLength(默认6)限定。 第3部分,序列数,是每毫秒下的序列数,由参数中的 SeqBitLength(默认6)限定。 💎 ID示例 🟣 本算法生成的 ID ,是一串整数,最多8字节。以下是基于默认配置生成的ID: 129053495681099 (本算法运行1年) 387750301904971 (运行3年) 646093214093387 (运行5年) 1292658282840139 (运行10年) 9007199254740992 (js Number 最大值) 165399880288699493 (普通雪花算法生成的ID) 🟣 本算法生成的 ID 值,是 js Number 最大值的 1%-10%,是普通雪花算法值的千分之一,而计算能力却超过普通雪花算法。 🟣 js Number 类型最大数值:9007199254740992,本算法在保持并发性能(5W+/0.01s)和最大64个 WorkerId(6bit)的同时,能用70年才到 js Number Max 值。 长度估算 💍 每增加 1位 WorkerIdBitLength 或 SeqBitLength,生成的ID数字值将会乘以2(基础长度可参考前“ID示例”),反之则除以2。 能用多久 🔵 在默认配置下,ID可用 71000 年不重复。 🔵 在支持 1024 个工作节点时,ID可用 4480 年不重复。 🔵 在支持 4096 个工作节点时,ID可用 1120 年不重复。 💎 参数设置 ❄ WorkerIdBitLength,机器码位长,决定 WorkerId 的最大值,默认值6,取值范围 [1, 19],实际上有些语言采用 无符号ushort(uint16) 类型接收该参数,所以最大值是16,如果是采用有符号short(int16),则最大值为15。 ❄ WorkerId,机器码,最重要参数,无默认值,必须由外部设定,默认情况下最大值63,理论最大值 2^WorkerIdBitLength-1(实际上根据语言的实现不同可能会限定在 65535 或 32767,原理同 WorkerIdBitLength 的规则)。不同机器或不同应用实例不可相同,你可通过应用程序配置该值,也可通过调用外部服务获取值。针对自动注册WorkerId需求,本算法提供默认实现:通过 redis 自动注册 WorkerId 的动态库,详见“Tools\AutoRegisterWorkerId”。 ❄ SeqBitLength,序列数位长,默认值6,取值范围 [3, 21](建议不小于4),决定每毫秒生成的 ID 个数。规则要求:WorkerIdBitLength + SeqBitLength 不超过 22。 ❄ MinSeqNumber,最小序列数,默认值5,取值范围 [5, MaxSeqNumber],每毫秒的前5个序列数对应编号0-4是保留位,其中1-4是时间回拨相应预留位,0是手工新值预留位。 ❄ MaxSeqNumber,最大序列数,设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值0,表示最大序列数取最大值(2^SeqBitLength-1),不为0时,用该设置值为最大序列数,一般无需设置最大序列数,除非多机共享WorkerId分段生成ID(此时还要正确设置最小序列数)。 💎 常规集成 1️⃣ 用单例模式调用。外部集成方使用更多的实例并行调用本算法,不会增加ID产出效能,因为本算法采用单线程模式生成ID。 2️⃣ 指定唯一的 WorkerId。必须由外部系统确保 WorkerId 的全局唯一性,并赋值给本算法入口方法。 3️⃣ 单机多实例部署时使用不同 WorkerId。并非所有实现都支持跨进程的并发唯一,保险起见,在同一主机上部署多应用实例时,请确保各 WorkerId 唯一。 4️⃣ 异常处理。算法会抛出所有 Exception,外部系统应 catch 异常并做好应对处理,以免引发更大的系统崩溃。 5️⃣ 认真理解 IdGeneratorOptions 的定义,这对集成和使用本算法有帮助。 6️⃣ 使用雪花漂移算法。虽然代码里包含了传统雪花算法的定义,并且你可以在入口处指定(Method=2)来启用传统算法,但仍建议你使用雪花漂移算法(Method=1,默认的),毕竟它具有更好的伸缩力和更高的性能。 7️⃣ 不要修改核心算法。本算法内部参数较多,逻辑较为复杂,在你尚未掌握核心逻辑时,请勿尝试修改核心代码且用于生产环境,除非通过大量细致、科学的测试验证。 💎 配置变更 配置变更指是系统运行一段时间后,再变更运行参数(IdGeneratorOptions选项值),请注意: 🔴 1.最重要的一条原则是:BaseTime 只能往前(比老值更小、距离现在更远)赋值,原因是往后赋值极大可能产生相同的时间戳。[不推荐在系统运行之后调整 BaseTime] 🔴 2.任何时候增加 WorkerIdBitLength 或 SeqBitLength,都是可以的,但是慎用 “减小”的操作,因为这可能导致在未来某天生成的 ID 与过去老配置时相同。[允许在系统运行之后增加任何一个 BitLength 值] 🔴 3.如果必须减小 WorkerIdBitLength 或 SeqBitLength 其中的一项,一定要满足一个条件:新的两个 BitLength 之和要大于 老的值之和。[不推荐在运行之后缩小任何一个 BitLength 值] 🔴 4.上述3条规则,并未在本算法内做逻辑控制,集成方应根据上述规则做好影响评估,确认无误后,再实施配置变更。 自动注册WorkerId 🔍 唯一ID生成器,依赖WorkerId,当业务服务需要水平无差别复制时,就要求它能自动注册全局唯一WorkerId,然后才能根据它生产唯一ID。 🔍 本算法提供一个开源动态库(go语言实现),能在容器 k8s(或其它容器化集群) 环境下,通过 redis 自动注册 WorkerId。 🔍 通过redis注册WorkerId,并不是唯一的方法。你也可以自己开发一个配置中心服务,各个应用服务启动时,通过配置中心获取唯一 WorkerId。 🔍 当然,如果你的服务不需要自动扩展,你就不必自动注册WorkerId,而是为每个应用手工设定一个唯一值。 自动注册流程图 图片链接:https://gitee.com/yitter/idgenerator/blob/master/Tools/AutoRegisterWorkerId/regprocess.jpg 源码路径:/Go/source/regworkerid/reghelper.go 动态库下载 下载链接:https://gitee.com/yitter/idgenerator/attach_files/662372/download/regworkerid_lib_v1.0.zip 动态库接口定义 // 注册一个 WorkerId,会先注销所有本机已注册的记录 // ip: redis 服务器地址 // port: redis 端口 // password: redis 访问密码,可为空字符串“” // maxWorkerId: 最大 WorkerId extern GoInt32 RegisterOne(char* ip, GoInt32 port, char* password, GoInt32 maxWorkerId); // 注销本机已注册的 WorkerId extern void UnRegister(); // 检查本地WorkerId是否有效(0-有效,其它-无效) extern GoInt32 Validate(GoInt32 workerId); 已实现的语言 语言 github gitee 🌲 C# 查看示例 查看示例 🌲 Java 查看示例 查看示例 🌲 Go 查看示例 查看示例 🌲 Rust 查看示例 查看示例 🌲 C 查看示例 查看示例 🌲 C (PHP扩展) 查看示例 查看示例 🌲 V 查看示例 查看示例 🌲 D 查看示例 查看示例 为什么不用大厂的? ❄ 首先,大厂们不但自己用雪花ID,而且还开源:百度 | 美团 | 滴滴 | 雪花ID鼻祖-推特。 ❄ 然而,大厂的雪花算法分为“经典算法”和“号段算法”两种,其中“号段算法”依赖网络或外部存储系统,不适合“非大厂”。 ❄ 至于其“经典算法”,在“ID长度和生成性能”方面,未做过优化,而这正式本算法——雪花漂移算法的核心所在。 技术支持 开源地址1:https://github.com/yitter/idgenerator 开源地址2:https://gitee.com/yitter/idgenerator QQ群:646049993

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册