SpringCloud Gateway 路由數量對性能的影響研究

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"背景描述","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"近期在公司建設API治理平臺過程中,以SpringCloud Gateway爲基礎,構建了一個API的Mock服務,以API的URI作爲路由,根據服務端存儲的API DSL,驗證請求信息,生成並返回Mock報文。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SpringCloud Gateway具備很好的動態路由支持功能,可以在API DSL創建的同時,創建一條Mock路由,這樣API DSL創建後,開發人員就可以使用Mock服務進行開發調試工作。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但作爲一個企業級應用,所管轄的API的數量衆多,SpringCloud Gateway在路由表急劇膨脹後的性能如何?目前沒有查閱到明確說明的資料。翻閱其源碼發現,斷言命中其實是進行的遍歷,這樣路由表膨脹時,路由性能存疑,需要進行驗證,根據驗證結果制定近一步優化方案。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"驗證方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"保持其他所有變量不變,僅調整路由表大小,使用JMH工具進行基準測試,得出路由表膨脹與路由性能的關係。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"需要編寫三個服務:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"路由網關","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"擋板服務(路由轉發的upstream)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"JMH測試端","attrs":{}}]}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/06/06b255247c0d3fdca28817341c74a03c.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"配置信息","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" CPU Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz\n\n 基準速度: 3.60 GHz\n 插槽: 1\n 內核: 8\n 邏輯處理器: 8\n 虛擬化: 已啓用\n L1 緩存: 512 KB\n L2 緩存: 2.0 MB\n L3 緩存: 12.0 MB\n\n 測試期間CPU利用率約 50%\n\n SpringCloud Gateway 3.0.3, Java 1.8.0_251\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"測試過程需控制變量,所以CPU負債不能過高,下圖是我執行測試時的CPU負載情況","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/4d/4d6e5b1e40bbb9be923103f5ada8c813.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"路由定義示例","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"json"},"content":[{"type":"text","text":"{\n \"_id\": {\n \"$oid\": \"60c4f055588bca06132e44cb\"\n },\n \"predicates\": [{\n \"name\": \"Path\",\n \"args\": {\n \"_genkey_0\": \"/1999\"\n }\n }],\n \"filters\": [{\n \"name\": \"AddRequestHeader\",\n \"args\": {\n \"_genkey_0\": \"x-benchmark-routeId\",\n \"_genkey_1\": \"60c4f055588bca06132e44cb\"\n }\n }, {\n \"name\": \"PrefixPath\",\n \"args\": {\n \"_genkey_0\": \"/ok\"\n }\n }],\n \"uri\": \"http://localhost:9999\",\n \"metadata\": {},\n \"order\": 1,\n \"_class\": \"com.example.scgw.benchmark.route.MongoRouteDefinition\"\n}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"測試結論","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/89/890d2c911d27e7a91cd10cc39a9f7954.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9a/9abea36021a70ccd2d4b2275e5957098.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"見上圖,測試結果無論系統的吞吐量,還是響應時間指標,都隨着路由表的膨脹變差,當路由表膨脹到10W級別時,服務基本不可用了!","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這一結論印證了我的猜想。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"優化思路一","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"保持路由網關的通用性(SpringCloud Gateway設計了很多路由斷言手段,包括基於path、method、header、parameter等等),採用兩級(多級)路由機制見下圖:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/97/972590a11210763e1d2386b363bae88b.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"優化思路二","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Mock服務是一個專有場景,僅根據Path和指定Header進行轉發,可以修改SpringCloud Gateway源碼,提供一個根據Path+指定Header查找路由的HashMap,這樣進行路由斷言時就不需進行路由表遍歷。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"個人傾向於按照思路二進行優化,優化過程見","attrs":{}},{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/bebacc42bad0712638ba3231e","title":"","type":null},"content":[{"type":"text","text":"SpringCloud Gateway 路由轉發性能優化","attrs":{}}]},{"type":"text","text":"。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"測試相關代碼","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"路由網關","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"pom.xml","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"xml"},"content":[{"type":"text","text":"\n org.springframework.boot\n spring-boot-starter-data-mongodb-reactive\n\n\n org.springframework.cloud\n spring-cloud-starter-gateway\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MongoRouteDefinition.java","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Document\npublic class MongoRouteDefinition extends RouteDefinition {\n\n @Id\n private String id;\n\n @Override\n public String getId() {\n return this.id;\n }\n\n @Override\n public void setId(String id) {\n this.id = id;\n }\n\n public static MongoRouteDefinition from(RouteDefinition route) {\n MongoRouteDefinition newRoute = new MongoRouteDefinition();\n BeanUtils.copyProperties(route, newRoute);\n return newRoute;\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MongoRouteRepository.java","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface MongoRouteRepository extends\n ReactiveMongoRepository {\n\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MongoRouteDefinitionRepository.java","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Component\npublic class MongoRouteDefinitionRepository implements RouteDefinitionRepository {\n\n private final MongoRouteRepository mongoRouteRepository;\n\n public MongoRouteDefinitionRepository(\n MongoRouteRepository mongoRouteRepository) {\n this.mongoRouteRepository = mongoRouteRepository;\n }\n\n @Override\n public Flux getRouteDefinitions() {\n return mongoRouteRepository.findAll().map(r -> r);\n }\n\n @Override\n public Mono save(Mono route) {\n return route.flatMap(\n r -> mongoRouteRepository.save(MongoRouteDefinition.from(r))\n .and(Mono.empty())\n );\n }\n\n @Override\n public Mono delete(Mono routeId) {\n return routeId.flatMap(mongoRouteRepository::deleteById);\n }\n\n public Mono save(MongoRouteDefinition route) {\n return mongoRouteRepository.save(route);\n }\n \n public Mono delete(String routeId) {\n return mongoRouteRepository.deleteById(routeId);\n }\n\n public Flux saveAll(Flux routes) {\n return mongoRouteRepository\n .saveAll(routes.map(MongoRouteDefinition::from));\n }\n\n public Flux saveAll(List routes) {\n return mongoRouteRepository.saveAll(routes);\n }\n\n public Mono deleteAll() {\n return mongoRouteRepository.deleteAll();\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MongoRouteDefinitionRepositoryTest.java","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@SpringBootTest\nclass MongoRouteDefinitionRepositoryTest {\n\n public static final String UP_STREAM = \"http://localhost:9999\";\n @Autowired\n MongoRouteDefinitionRepository mongoRepository;\n\n @Test\n void save() {\n Mono route = mongoRepository.save(newRoute(-1));\n\n StepVerifier.create(route)\n .expectNextMatches(r -> r.getId() != null)\n .expectComplete()\n .verify();\n }\n\n @Test\n void saveAll() {\n this.deleteAll();\n int cycle = 100;\n while (cycle-- > 0) {\n int count = 100;\n List routes = new ArrayList<>(count);\n while (count-- > 0) {\n routes.add(newRoute(cycle * 100 + count));\n }\n mongoRepository.saveAll(routes).blockLast();\n }\n }\n\n @Test\n void deleteAll() {\n mongoRepository.deleteAll().block();\n }\n\n private MongoRouteDefinition newRoute(int path) {\n MongoRouteDefinition route = new MongoRouteDefinition();\n route.setId(ObjectId.get().toHexString());\n PredicateDefinition predicate = new PredicateDefinition(\n \"Path=/mock/\" + path);\n route.setPredicates(Collections.singletonList(predicate));\n List filters = new LinkedList<>();\n filters.add(new FilterDefinition(\"AddRequestHeader=x-benchmark-routeId,\" + route.getId()));\n filters.add(new FilterDefinition(\"PrefixPath=/ok\"));\n route.setFilters(filters);\n route.setOrder(1);\n route.setUri(URI.create(UP_STREAM));\n return route;\n }","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"application.properties","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"properties"},"content":[{"type":"text","text":"server.port=9999","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"擋板服務","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"pom.xml","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"xml"},"content":[{"type":"text","text":"\n org.springframework.boot\n spring-boot-starter-webflux\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"java","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class MockApplication {\n\n public static void main(String[] args) {\n SpringApplication.run(MockApplication.class, args);\n }\n \n @Bean\n RouterFunction defaultRouter() {\n return route(path(\"/ok/**\"), this::success);\n }\n\n Mono success(ServerRequest request) {\n String routeId = request.headers().firstHeader(\"x-benchmark-routeId\");\n return ok()\n .header(\"x-mock-server-routeId\", routeId)\n .contentType(MediaType.TEXT_PLAIN)\n .body(Mono.just(String.valueOf(routeId)), String.class);\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"application.properties","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"properties"},"content":[{"type":"text","text":"server.port=9999","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"JMH 代碼","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"創建工程","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"mvn archetype:generate \\\n -DinteractiveMode=false \\\n -DarchetypeGroupId=org.openjdk.jmh \\\n -DarchetypeArtifactId=jmh-java-benchmark-archetype \\\n -DgroupId=com.example \\\n -DartifactId=jmh \\\n -Dversion=1.32","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"修改POM文件","attrs":{}},{"type":"text","text":",添加http客戶端依賴","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"xml"},"content":[{"type":"text","text":"\n com.squareup.okhttp3\n okhttp\n 4.9.1\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"編寫測試案例","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class MyBenchmark {\n\n @Benchmark\n @Threads(2)\n @Fork(2)\n @BenchmarkMode(Mode.All)\n @Warmup(iterations = 1, time = 3)\n @Measurement(iterations = 10, time = 1)\n @Timeout(time = 300)\n public void testMethod() {\n // 根據路由總數設置隨機路由path\n int path = (int) (Math.random() * 100000);\n testRoute(path);\n }\n\n /**\n * 待測試方法\n */\n public void testRoute(int path) {\n OkHttpClient client = new OkHttpClient();\n Request request = new Request.Builder()\n .url(\"http://127.0.0.1:8888/mock/\" + path)\n .build();\n Call call = client.newCall(request);\n try {\n Response response = call.execute();\n assert response.body() != null;\n } catch (Exception e) {\n e.printStackTrace();\n }\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"執行性能基準測試","attrs":{}},{"type":"text","text":":","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"方式1,IDEA的JMH插件JMH plugin安裝後,直接在IDEA裏運行;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"方式2,mvn 打包,執行jar包","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"mvn package\njava -jar target/benchmarks.jar\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"收集測試結果","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"測試結果數據見下文,共6組。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"測試數據","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"對照組(直連)","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"Benchmark Mode Cnt Score Error Units\nMyBenchmark.testMethod thrpt 20 899.152 ± 137.062 ops/s\nMyBenchmark.testMethod avgt 20 0.002 ± 0.001 s/op\nMyBenchmark.testMethod sample 17647 0.002 ± 0.001 s/op\nMyBenchmark.testMethod:testMethod·p0.00 sample 0.001 s/op\nMyBenchmark.testMethod:testMethod·p0.50 sample 0.002 s/op\nMyBenchmark.testMethod:testMethod·p0.90 sample 0.003 s/op\nMyBenchmark.testMethod:testMethod·p0.95 sample 0.003 s/op\nMyBenchmark.testMethod:testMethod·p0.99 sample 0.003 s/op\nMyBenchmark.testMethod:testMethod·p0.999 sample 0.012 s/op\nMyBenchmark.testMethod:testMethod·p0.9999 sample 0.018 s/op\nMyBenchmark.testMethod:testMethod·p1.00 sample 0.018 s/op\nMyBenchmark.testMethod ss 20 0.003 ± 0.001 s/op","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"100條路由","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"Benchmark Mode Cnt Score Error Units\nMyBenchmark.testMethod thrpt 20 713.931 ± 97.302 ops/s\nMyBenchmark.testMethod avgt 20 0.003 ± 0.001 s/op\nMyBenchmark.testMethod sample 14090 0.003 ± 0.001 s/op\nMyBenchmark.testMethod:testMethod·p0.00 sample 0.002 s/op\nMyBenchmark.testMethod:testMethod·p0.50 sample 0.003 s/op\nMyBenchmark.testMethod:testMethod·p0.90 sample 0.004 s/op\nMyBenchmark.testMethod:testMethod·p0.95 sample 0.004 s/op\nMyBenchmark.testMethod:testMethod·p0.99 sample 0.005 s/op\nMyBenchmark.testMethod:testMethod·p0.999 sample 0.008 s/op\nMyBenchmark.testMethod:testMethod·p0.9999 sample 0.011 s/op\nMyBenchmark.testMethod:testMethod·p1.00 sample 0.011 s/op\nMyBenchmark.testMethod ss 20 0.003 ± 0.001 s/op","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1000條路由","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"Benchmark Mode Cnt Score Error Units\nMyBenchmark.testMethod thrpt 20 630.823 ± 41.301 ops/s\nMyBenchmark.testMethod avgt 20 0.003 ± 0.001 s/op\nMyBenchmark.testMethod sample 12617 0.003 ± 0.001 s/op\nMyBenchmark.testMethod:testMethod·p0.00 sample 0.002 s/op\nMyBenchmark.testMethod:testMethod·p0.50 sample 0.003 s/op\nMyBenchmark.testMethod:testMethod·p0.90 sample 0.004 s/op\nMyBenchmark.testMethod:testMethod·p0.95 sample 0.004 s/op\nMyBenchmark.testMethod:testMethod·p0.99 sample 0.005 s/op\nMyBenchmark.testMethod:testMethod·p0.999 sample 0.008 s/op\nMyBenchmark.testMethod:testMethod·p0.9999 sample 0.009 s/op\nMyBenchmark.testMethod:testMethod·p1.00 sample 0.009 s/op\nMyBenchmark.testMethod ss 20 0.004 ± 0.001 s/op","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"5000條路由","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"Benchmark Mode Cnt Score Error Units\nMyBenchmark.testMethod thrpt 20 248.353 ± 4.634 ops/s\nMyBenchmark.testMethod avgt 20 0.008 ± 0.001 s/op\nMyBenchmark.testMethod sample 5007 0.008 ± 0.001 s/op\nMyBenchmark.testMethod:testMethod·p0.00 sample 0.002 s/op\nMyBenchmark.testMethod:testMethod·p0.50 sample 0.009 s/op\nMyBenchmark.testMethod:testMethod·p0.90 sample 0.009 s/op\nMyBenchmark.testMethod:testMethod·p0.95 sample 0.011 s/op\nMyBenchmark.testMethod:testMethod·p0.99 sample 0.014 s/op\nMyBenchmark.testMethod:testMethod·p0.999 sample 0.017 s/op\nMyBenchmark.testMethod:testMethod·p0.9999 sample 0.019 s/op\nMyBenchmark.testMethod:testMethod·p1.00 sample 0.019 s/op\nMyBenchmark.testMethod ss 20 0.009 ± 0.001 s/op","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1w條路由","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"Benchmark Mode Cnt Score Error Units\nMyBenchmark.testMethod thrpt 20 131.585 ± 1.799 ops/s\nMyBenchmark.testMethod avgt 20 0.015 ± 0.001 s/op\nMyBenchmark.testMethod sample 2671 0.015 ± 0.001 s/op\nMyBenchmark.testMethod:testMethod·p0.00 sample 0.002 s/op\nMyBenchmark.testMethod:testMethod·p0.50 sample 0.016 s/op\nMyBenchmark.testMethod:testMethod·p0.90 sample 0.017 s/op\nMyBenchmark.testMethod:testMethod·p0.95 sample 0.018 s/op\nMyBenchmark.testMethod:testMethod·p0.99 sample 0.028 s/op\nMyBenchmark.testMethod:testMethod·p0.999 sample 0.030 s/op\nMyBenchmark.testMethod:testMethod·p0.9999 sample 0.030 s/op\nMyBenchmark.testMethod:testMethod·p1.00 sample 0.030 s/op\nMyBenchmark.testMethod ss 20 0.016 ± 0.001 s/op","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"10W條路由","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"Benchmark Mode Cnt Score Error Units\nMyBenchmark.testMethod thrpt 20 13.880 ± 0.364 ops/s\nMyBenchmark.testMethod avgt 20 0.141 ± 0.002 s/op\nMyBenchmark.testMethod sample 300 0.141 ± 0.002 s/op\nMyBenchmark.testMethod:testMethod·p0.00 sample 0.005 s/op\nMyBenchmark.testMethod:testMethod·p0.50 sample 0.141 s/op\nMyBenchmark.testMethod:testMethod·p0.90 sample 0.142 s/op\nMyBenchmark.testMethod:testMethod·p0.95 sample 0.143 s/op\nMyBenchmark.testMethod:testMethod·p0.99 sample 0.144 s/op\nMyBenchmark.testMethod:testMethod·p0.999 sample 0.270 s/op\nMyBenchmark.testMethod:testMethod·p0.9999 sample 0.270 s/op\nMyBenchmark.testMethod:testMethod·p1.00 sample 0.270 s/op\nMyBenchmark.testMethod ss 20 0.141 ± 0.001 s/op","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章