{"id":33179000,"url":"https://github.com/PhantomThief/simple-failover-java","last_synced_at":"2025-11-20T21:03:09.608Z","repository":{"id":32082767,"uuid":"35654770","full_name":"PhantomThief/simple-failover-java","owner":"PhantomThief","description":"A simple failover library for Java","archived":false,"fork":false,"pushed_at":"2023-12-05T22:19:07.000Z","size":387,"stargazers_count":159,"open_issues_count":5,"forks_count":52,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-08-02T01:47:48.250Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"artistic-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PhantomThief.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-15T05:12:47.000Z","updated_at":"2025-07-15T15:21:41.000Z","dependencies_parsed_at":"2022-06-29T21:04:12.159Z","dependency_job_id":null,"html_url":"https://github.com/PhantomThief/simple-failover-java","commit_stats":null,"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"purl":"pkg:github/PhantomThief/simple-failover-java","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomThief%2Fsimple-failover-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomThief%2Fsimple-failover-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomThief%2Fsimple-failover-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomThief%2Fsimple-failover-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PhantomThief","download_url":"https://codeload.github.com/PhantomThief/simple-failover-java/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomThief%2Fsimple-failover-java/sbom","scorecard":{"id":109602,"data":{"date":"2025-08-11","repo":{"name":"github.com/PhantomThief/simple-failover-java","commit":"c024cb9ab8e77784ba10af5b3da3d82da5c7cd35"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":2,"reason":"Found 6/30 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Artistic License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-5mg8-w23w-74h3","Warn: Project is vulnerable to: GHSA-7g45-4rm6-3mm3"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-15T11:49:42.776Z","repository_id":32082767,"created_at":"2025-08-15T11:49:42.776Z","updated_at":"2025-08-15T11:49:42.776Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285511775,"owners_count":27184237,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-20T02:00:05.334Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-11-16T03:00:36.817Z","updated_at":"2025-11-20T21:03:09.603Z","avatar_url":"https://github.com/PhantomThief.png","language":"Java","funding_links":[],"categories":["容错组件"],"sub_categories":[],"readme":"simple-failover-java\n=======================\n[![Build Status](https://travis-ci.org/PhantomThief/simple-failover-java.svg)](https://travis-ci.org/PhantomThief/simple-failover-java)\n[![Coverage Status](https://coveralls.io/repos/PhantomThief/simple-failover-java/badge.svg?branch=master)](https://coveralls.io/r/PhantomThief/simple-failover-java?branch=master)\n[![Total alerts](https://img.shields.io/lgtm/alerts/g/PhantomThief/simple-failover-java.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/PhantomThief/simple-failover-java/alerts/)\n[![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/PhantomThief/simple-failover-java.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/PhantomThief/simple-failover-java/context:java)\n[![Maven Central](https://img.shields.io/maven-central/v/com.github.phantomthief/simple-failover)](https://search.maven.org/artifact/com.github.phantomthief/simple-failover/)\n\nA simple failover library for Java.\n\n用于构建高性能的客户端（主调方）自适应负载均衡和自动重试能力。\n\n* jdk1.8+\n\n## Get Started\n\n```Java\t\n// 添加多个被调用资源，这里的被调用资源是指目标服务器（有多个服务器提供相同的服务），下面例子展示了3个，每个权重100\nString server1 = \"192.168.1.1\";\nString server1 = \"192.168.1.2\";\nString server1 = \"192.168.1.3\";\nSimpleFailover\u003cString\u003e failover = PriorityFailover.newBuilder()\n        .addResource(server1, 100.0) \n        .addResource(server2, 100.0)\n        .addResource(server3, 100.0)\n        .build();\nString server = failover.getOneAvailable();\n// 获取一个资源执行操作，上面添加了3个，并且初始权重相同，所以刚开始的时候每个资源被选中的概率是1/3\nboolean success = doSomethingWithServer(server);\nif(success) {\n    // 成功会增加权重，最大不会超过上面指定的100\n    failover.success(server);\n} else {\n    // 失败扣减权重，降低下次被选择的概率，最小扣到0\n    failover.fail(server);\n\n    // 如果需要重试1次\n    server = failover.getOneAvailableExclude(Collections.singleton(server));\n    doSomethingWithServer(server);\n    // ...\n}\n```\n\n## 性能\n本类库设计用来支撑百万TPS（单主调方）级别的RPC client的构建，因此它本身要达到千万TPS级别才能保证不成为瓶颈。\n\n* 当被调资源全部完全健康（当前权重=最大权重）且最大权重相同时，使用round robin算法，时间复杂度O(1)\n* 当被调资源数\u003e10，最大权重不同，且全部完全健康时，使用AliasMethod算法，时间复杂度O(1)\n* 其它情况下时间复杂度为O(N)。当开启了优先级分组以后，N为最高优先级的资源数，这个数字通常较小，从而大幅提升了性能。\n\n核心类PriotiryFailover是线程安全的，无锁实现保证高性能。\nPriorityFailoverManager/PriorityGroupManager的变更方法（通常资源上下线才使用）都不是线程安全的，变更时请自行加锁，PriorityFailoverBuilder类一般来说是使用完就丢弃的，也不是线程安全的。\n\n单元测试代码中BenchmarkMain类可以用来做性能测试，文末有测试结果表，不同的工况下有不同的性能数值，整个表格中只有单线程N较大的一个场景下没有达标，大部分场景都可以达到数千万TPS。\n\n\n## cookbook\n### 定制权重增加和扣减策略\n默认情况下，每次调用失败将当前权重减半，例如：\n初始权重100.0，第一次失败后（调用fail方法后）权重为50.0，第二次失败后25.0，第三次失败后12.5。\n\n每次成功后将增加最大权重的1%，例如：\n最大权重100，当前权重12.5，成功后（调用success方法后），权重为13.5。\n\n所以这个默认算法是等比递减、等差递增。等比递减可以保证被调用服务器不稳定的情况下权重迅速下降（尽快摘除）。如果需要调整参数：\n```java\nPriorityFailoverBuilder\u003cString\u003e buidler = PriorityFailover.newBuilder();\n// 每次失败后只保留当前权重的0.1，成功后增加最大权重的0.01\nbuidler.weightFunction(new RatioWeightFunction(\n          /*failKeepRateOfCurrentWeight*/0.1, /*successIncreaseRateOfMaxWeight*/0.01));\n```\n\n如果想等差扣减权重：\n```java\n// 每次失败后扣酱最大权重的0.05，成功后增加最大权重的0.01\nbuidler.weightFunction(new SimpleWeightFunction(\n          /*failDecreaseRate*/0.05, /*successIncreaseRate*/0.01));\n```\n\n### 主动健康检查\n不健康的资源，通过后台线程运行主动健康检查恢复权重，需要设置检查器和检查间隔参数：\n```java\nbuidler.checker(server -\u003e pingServer(server));\nbuilder.checkDuration(Duration.ofSeconds(60));\n```\n默认情况下，权重变成0算作不健康，健康检查成功1次就立刻恢复权重。这个行为可以通过WeightFunction定制：\n```java\nbuidler.weightFunction(new RatioWeightFunction(/*failKeepRateOfCurrentWeight*/0.5, \n        /*successIncreaseRateOfMaxWeight*/0.01, /*recoverThreshold*/2, /*downThreshold*/0.1));\n```\n以上第一个参数指定每次调用失败后权重减半，第二个参数指定调用成功后增加最大权重的0.01，第三个参数指定调用主动健康检查连续成功两次才可以增加权重（增加的数值由第二个参数指定），第四个参数指定当前权重小于0.1以后直接变成为0（否则等比递减很难减少到0，此时不会有主动健康检查）。\n\n如果希望完全健康的时候也执行健康检查也可以通过weightFunction覆盖needCheck方法来定制。\n另外检查任务是懒启动的，需要有一次fail或者down的调用才会启动，如果不想这样（例如完全健康的节点也想定期检查），可以在builder上设置startCheckTaskImmediately。\n\n### 最小权重\n一般来说最小权重就是0，一个资源连续调用失败，它的权重应该被扣减到0，以免新的请求发到它那里去。\n\n但有的时候我们不想这样，比如，我们总共只有两个集群，希望无论如何都选择一个相对健康的集群发送请求，可以通过以下代码指定最小权重是0.1：\n```java\nSimpleFailover\u003cString\u003e failover = PriorityFailover.newBuilder()\n        .addResource(server1, /*maxWeight*/100.0, /*minWeight*/0.1) \n...\n```\n\n### 运行时变更资源列表\n主调方已经启动的情况下，被调资源有变动，这在分布式rpc场景是很常见的，可以通过\n```java\nObject server1 = \"s1\";\nObject server2 = \"s2\";\nObject server3 = \"s3\";\nPriorityFailoverManager\u003cObject\u003e manager = PriorityFailover.newBuilder()\n        .addResource(server1, 100)\n        .addResource(server2, 100)\n        .buildManager();\nObject obj = manager.getFailover().getOneAvailable();\n// 总是通过manager拿到PriorityFailover来用\n\n// 当资源需要变更的时候\nHashMap\u003cObject, ResConfig\u003e map = new HashMap\u003c\u003e();\nmap.put(server2, new ResConfig(/*maxWeight*/100));\nmap.put(server3, new ResConfig(/*maxWeight*/100));\nmanager.updateAll(map); //还有个update方法可以做增量更新\n\n// 之后manager.getFailover()取出来的是个新的failover，删除了server1，添加了server3\n```\n变更后原有资源（上面的例子是server2）的权重会从之前的failover继承下来。updateAll的时候最大权重等参数可以改。\n\n以上代码展示了全量变更，通过update方法可以实现增量变更。\n\n### 预热/慢启动\n上面的代码中，server3是个新加的资源，为了防止新上线的实例被打爆，我们可以把它的初始权重设置为5。\n```java\nmap.put(server3, new ResConfig(/*maxWeight*/100, /*minWeight*/0, /*priority*/0, /*initWeight*/5));\n```\n这样，新上的server3只有5%的流量，随着调用的成功，它的权重会慢慢增加到100。\n\n### 并发度控制（自适应负载均衡）\n多个被调资源的性能能力可能是不一样的，可能是因为硬件性能不同，也可能是某个资源上还运行了其它服务等原因。\n虽然我们可以在addResource的时候为它们设置不同的最大权重，但是复杂场景下我们很难估计好不同资源之间的最大权重比，何况资源的能力可能在运行时变化。\n假设现在有个被调资源在有性能压力，刚开始不会失败，如果持续高流量进入，会导致这个对这个资源的调用开始出错。所以我们希望，当某个资源有性能问题的苗头时，就减少对它的流量。\n\n这个性能问题可以通过响应时间反应出来，在我们的代码中也就是调用getOneAvailable和调用success/fail的时间差。所以我们引入并发度的概念：\n```java\nbuilder.concurrencyControl(true);\n```\n通过以上代码激活并发度控制，并发度高的资源，流量会减少。\n并发度初始值是0，getOneAvailable会将并发度加1，success/fail/down会将并发度减1，内部选择资源的时候，当前权重会除以（并发度+1），也就是说如果并发度为1，有效权重就会减半（除以2），并发度是2时，有效权重就会变为1/3。\n\n有个要求是getOneAvailable取出来的资源用完后，必须通过success/fail/down放回去，否则并发度计算会错误。\n\n### 资源优先级\n被调资源很多的情况下（比如有1000台服务器），我们不想把请求均匀的发到这些服务器上，因为这会导致：\n1. 导致底下的网络长连接、连接池不能很好的复用\n2. 如果主调方的访问的数据有局部性，可能导致被调方缓存命中率降低\n3. 被调方和主调方可能位置相关的特性，比如机房、可用区，希望调用时本地优先\n\n构建的时候：\n```java\n.addResource(server1, /*maxWeight*/100, /*minWeight*/0, /*priority*/0, /*initWeight*/100))\n.addResource(server2, /*maxWeight*/100, /*minWeight*/0, /*priority*/0, /*initWeight*/100))\n.addResource(server3, /*maxWeight*/100, /*minWeight*/0, /*priority*/1, /*initWeight*/100))\n.addResource(server4, /*maxWeight*/100, /*minWeight*/0, /*priority*/1, /*initWeight*/100))\n```\n以上4个服务器分为2个group，当优先级为0的group变的不健康以后，流量会逐渐溢出到优先级为1的group。具体可看PriorityFailover设计。\n\n注意流量是逐渐溢出的，具体算法与[envoy](https://www.servicemesher.com/envoy/intro/arch_overview/load_balancing.html)类似，默认因子也是1.4，如果想要第一个group里面的资源死光光以后再溢出，可以在builder上设置：\n```java\nbuilder.priorityFactor(Double.MAX_VALUE)\n```\n### 自动优先级管理\n比如，机房里有300个RPC被调资源，想分为2组，第一组5个，剩下的归为第二组：\n```java\nbuilder.enableAutoPriority(5);\n```\n\n如果希望分3组，第一个组5个，第二组20个，剩下的归为第三组，可以这样：\n```java\nbuilder.enableAutoPriority(5, 20)\n```\n\nPriorityFailoverManager也能够支持自动优先级管理。\n\n使用自动优先级管理，资源变更时，新增的资源和已有资源一样有均等的机会进入高优先级组；\n同时已有的资源本来会在高优先级组的仍然会优先，以尽量保持调用的粘性，减少变更的影响，详见PriorityGroupManager类。\n\n### 资源事件通知（比如资源down）\n可以在builder上设置weightListener：\n\n```java\npublic interface WeightListener\u003cT\u003e {\n    void onSuccess(double maxWeight, double minWeight, double currentNewWeight, T resource);\n\n    void onFail(double maxWeight, double minWeight, double currentNewWeight, T resource);\n}\n```\n需要注意这个回调仅在资源权重变更的时候触发（完全健康状态下再次成功是没有onSuccess回调的，onFail也类似）。\n\n\n## benchmark测试结果表\n\n* 测试环境，笔记本，I7-9750H，6核12线程，2.6G~4.5G\n* Score数值为千TPS，即要乘以1000。\n* concurrencyCtrl代表是否打开并发度控制，totalSize代表资源数，coreSize代表分2组优先级情况下，priority=0的资源数，剩下的priority=1。\n* getOneSuccess代表getOneAvailable获取资源以后，接下来调用failover.success(res)方法，模拟资源调用成功。\n* getOneFail代表getOneAvailable获取资源以后，模拟1/1000的资源调用失败。资源调用失败会造成性能failover劣化，时间复杂度会退化到O(N)，同时多线程场景下对volatile变量的写也会导致性能降低。\n\n1线程：\n```\nBenchmark                             (concurrencyCtrl)  (coreSize)  (totalSize)   Mode  Cnt      Score   Error  Units\nGroup1PriorityFailover.getOneFail                   N/A         N/A            5  thrpt    2  66408.751          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A           20  thrpt    2  68001.154          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A          100  thrpt    2  47727.860          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A          200  thrpt    2  25812.804          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A         1000  thrpt    2   2433.041          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A            5  thrpt    2  95741.988          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A           20  thrpt    2  92530.019          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A          100  thrpt    2  85027.270          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A          200  thrpt    2  84072.456          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A         1000  thrpt    2  56069.687          ops/s\nGroup2PriorityFailover.getOneFail                  true           5         1000  thrpt    2  17725.844          ops/s\nGroup2PriorityFailover.getOneFail                  true          20         1000  thrpt    2   9911.852          ops/s\nGroup2PriorityFailover.getOneFail                 false           5         1000  thrpt    2  66638.774          ops/s\nGroup2PriorityFailover.getOneFail                 false          20         1000  thrpt    2  65462.617          ops/s\nGroup2PriorityFailover.getOneSuccess               true           5         1000  thrpt    2  17721.040          ops/s\nGroup2PriorityFailover.getOneSuccess               true          20         1000  thrpt    2  10192.638          ops/s\nGroup2PriorityFailover.getOneSuccess              false           5         1000  thrpt    2  84482.401          ops/s\nGroup2PriorityFailover.getOneSuccess              false          20         1000  thrpt    2  87764.225          ops/s\n```\n\n5线程：\n```\nBenchmark                             (concurrencyCtrl)  (coreSize)  (totalSize)   Mode  Cnt      Score   Error  Units\nGroup1PriorityFailover.getOneFail                   N/A         N/A            5  thrpt    2  35019.174          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A           20  thrpt    2  29588.433          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A          100  thrpt    2  24206.241          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A          200  thrpt    2  26622.312          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A         1000  thrpt    2  13794.910          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A            5  thrpt    2  39493.298          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A           20  thrpt    2  37636.730          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A          100  thrpt    2  39736.684          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A          200  thrpt    2  40909.686          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A         1000  thrpt    2  44379.175          ops/s\nGroup2PriorityFailover.getOneFail                  true           5         1000  thrpt    2  13332.955          ops/s\nGroup2PriorityFailover.getOneFail                  true          20         1000  thrpt    2  12736.631          ops/s\nGroup2PriorityFailover.getOneFail                 false           5         1000  thrpt    2  30005.073          ops/s\nGroup2PriorityFailover.getOneFail                 false          20         1000  thrpt    2  29428.004          ops/s\nGroup2PriorityFailover.getOneSuccess               true           5         1000  thrpt    2  15578.987          ops/s\nGroup2PriorityFailover.getOneSuccess               true          20         1000  thrpt    2  20515.372          ops/s\nGroup2PriorityFailover.getOneSuccess              false           5         1000  thrpt    2  38486.222          ops/s\nGroup2PriorityFailover.getOneSuccess              false          20         1000  thrpt    2  37179.500          ops/s\n```\n\n200线程\n```\nBenchmark                             (concurrencyCtrl)  (coreSize)  (totalSize)   Mode  Cnt      Score   Error  Units\nGroup1PriorityFailover.getOneFail                   N/A         N/A            5  thrpt    2  45083.860          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A           20  thrpt    2  43295.450          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A          100  thrpt    2  39304.540          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A          200  thrpt    2  39092.222          ops/s\nGroup1PriorityFailover.getOneFail                   N/A         N/A         1000  thrpt    2  26619.782          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A            5  thrpt    2  60798.031          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A           20  thrpt    2  59382.891          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A          100  thrpt    2  60453.622          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A          200  thrpt    2  58952.071          ops/s\nGroup1PriorityFailover.getOneSuccess                N/A         N/A         1000  thrpt    2  55245.930          ops/s\nGroup2PriorityFailover.getOneFail                  true           5         1000  thrpt    2  17456.668          ops/s\nGroup2PriorityFailover.getOneFail                  true          20         1000  thrpt    2  19482.938          ops/s\nGroup2PriorityFailover.getOneFail                 false           5         1000  thrpt    2  41700.014          ops/s\nGroup2PriorityFailover.getOneFail                 false          20         1000  thrpt    2  40878.123          ops/s\nGroup2PriorityFailover.getOneSuccess               true           5         1000  thrpt    2  23196.162          ops/s\nGroup2PriorityFailover.getOneSuccess               true          20         1000  thrpt    2  31493.098          ops/s\nGroup2PriorityFailover.getOneSuccess              false           5         1000  thrpt    2  54561.672          ops/s\nGroup2PriorityFailover.getOneSuccess              false          20         1000  thrpt    2  53995.894          ops/s\n``` \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPhantomThief%2Fsimple-failover-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPhantomThief%2Fsimple-failover-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPhantomThief%2Fsimple-failover-java/lists"}