V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
newmiao
V2EX  ›  Go 编程语言

OPA 进阶-测试、性能分析和基准测试

  •  
  •   newmiao · 2020-04-06 18:43:50 +08:00 · 1376 次点击
    这是一个创建于 1452 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本文来讲讲OPA的测试(test)、性能分析(profile)和(benchmark

    掌握他们,对于保证策略代码的质量和决策效率有很大的帮助

    test

    OPA的测试很简单。

    所有test_前缀的的规则(rule)都是测试。

    Tips: 虽然是测试,但其本质上其仍是规则,仍然可以被查询。 另外建议文件名遵循_test.rego后缀加以区分

    这里拿quick-start的测试例子来看下:

    package example_rbac_test
    
    import data.example_rbac
    
    test_not_allow {
        not example_rbac.allow with input as {}
    }
    
    test_allow {
      example_rbac.allow with input as {
        "action": {
          "operation": "read",
          "resource": "widgets",
        },
        "subject": {"user": "inspector-alice"},
      }
    }
      
    

    就这样即覆盖了allow规则的全部测试用例。

    注意这里with起到了数据模拟的作用(data mocking

    Tips: 函数不可用with替换

    对应的命令行是:

    cd quick-start
    opa test . -v
    # 输出如下
    data.example_rbac_test.test_not_allow: PASS (693.201µs)
    data.example_rbac_test.test_allow: PASS (562.02µs)
    --------------------------------------------------------------------------------
    PASS: 2/2
    

    也可以查看测试覆盖率:

    opa test . -c

    设定测试覆盖率标准:

    opa test . -c --threshold 100

    (这里提示下别忘了vscode-opa支持可视化覆盖率展示哦)

    也支持选择测试用例执行:

    opa test -r test_allow . -v

    profile

    cd quick-start
    opa eval --profile -d example.rego -d data.json -i input.json -f pretty "data.example_rbac.allow"  
    
    true
    +------------------------------+---------+
    |            METRIC            |  VALUE  |
    +------------------------------+---------+
    | timer_rego_data_parse_ns     | 18332   |
    | timer_rego_load_files_ns     | 5506307 |
    | timer_rego_module_compile_ns | 573408  |
    | timer_rego_module_parse_ns   | 5226456 |
    | timer_rego_query_compile_ns  | 87390   |
    | timer_rego_query_eval_ns     | 292198  |
    | timer_rego_query_parse_ns    | 277932  |
    +------------------------------+---------+
    +----------+----------+----------+-------------------------+
    |   TIME   | NUM EVAL | NUM REDO |        LOCATION         |
    +----------+----------+----------+-------------------------+
    | 54.121µs | 1        | 1        | data.example_rbac.allow |
    | 42.776µs | 1        | 2        | example.rego:15         |
    | 37.861µs | 1        | 1        | example.rego:9          |
    | 35.81µs  | 1        | 1        | example.rego:25         |
    | 22.469µs | 1        | 1        | example.rego:10         |
    | 21.353µs | 2        | 2        | example.rego:16         |
    | 16.888µs | 2        | 1        | example.rego:17         |
    | 15.923µs | 2        | 1        | example.rego:23         |
    | 14.736µs | 1        | 2        | example.rego:22         |
    | 8.798µs  | 1        | 1        | example.rego:24         |
    +----------+----------+----------+-------------------------+
    

    Tips: --profile 还支持结果排序和限制显示条数

    • --profile-sort:对性能分析结果排序,默认按total_time_ns => num_eval => num_redo => file => line排序, 详见profile-sort 文档
    • --profile-limit:显示几条分析结果,默认 10 条

    benchmark

    opa 也支持benchmark,基本实现了gobenchmark的使用方式, 甚至有更详细的结果(毕竟一直标榜性能么)

    默认benchmark会展示内存(--benchmem)和查询(--metrics)的基准测试结果

    $ opa bench --count 1 -d example.rego -d data.json -i input.json -f pretty "data.example_rbac.allow"
    +-------------------------------------------+------------+
    | samples                                   |      14162 |
    | ns/op                                     |      93655 |
    | B/op                                      |      15117 |
    | allocs/op                                 |        311 |
    | histogram_timer_rego_query_eval_ns_75%    |      89900 |
    | histogram_timer_rego_query_eval_ns_90%    |     112253 |
    | histogram_timer_rego_query_eval_ns_95%    |     125465 |
    | histogram_timer_rego_query_eval_ns_99%    |     222404 |
    | histogram_timer_rego_query_eval_ns_99.9%  |     549291 |
    | histogram_timer_rego_query_eval_ns_99.99% |     550611 |
    | histogram_timer_rego_query_eval_ns_count  |      14162 |
    | histogram_timer_rego_query_eval_ns_max    |     550611 |
    | histogram_timer_rego_query_eval_ns_mean   |      76735 |
    | histogram_timer_rego_query_eval_ns_median |      68336 |
    | histogram_timer_rego_query_eval_ns_min    |      38896 |
    | histogram_timer_rego_query_eval_ns_stddev |      38828 |
    +-------------------------------------------+------------+
    

    当然也集成到了opa test

    $ opa test -v --bench  example.rego example_test.rego data.json 
    data.example_rbac_test.test_not_allow      15139             74172 ns/op             62044 timer_rego_query_eval_ns/op     14666 B/op     270 allocs/op
    data.example_rbac_test.test_allow          10000            102658 ns/op             90779 timer_rego_query_eval_ns/op     17825 B/op     367 allocs/op
    --------------------------------------------------------------------------------
    PASS: 2/2
    

    而且--format指定gobench的话,还支持了benchstat, 是Go亲生的,无疑了

    opa test -v --bench --count 5 --format gobench   example.rego example_test.rego data.json| tee b.txt
    
    BenchmarkDataExampleRbacTestTestNotAllow           15186             87349 ns/op             73644 timer_rego_query_eval_ns/op     14663 B/op        270 allocs/op
    BenchmarkDataExampleRbacTestTestAllow      10000            115857 ns/op            101565 timer_rego_query_eval_ns/op     17828 B/op        367 allocs/op
    --------------------------------------------------------------------------------
    PASS: 2/2
    ...
    
    benchstat b.txt
    
    name                             time/op
    DataExampleRbacTestTestNotAllow                  92.9µs ±40%
    DataExampleRbacTestTestAllow                      123µs ± 8%
    
    name                             timer_rego_query_eval_ns/op
    DataExampleRbacTestTestNotAllow                   79.0k ±41%
    DataExampleRbacTestTestAllow                       109k ± 9%
    
    name                             alloc/op
    DataExampleRbacTestTestNotAllow                  14.7kB ± 0%
    DataExampleRbacTestTestAllow                     17.8kB ± 0%
    
    name                             allocs/op
    DataExampleRbacTestTestNotAllow                     270 ± 0%
    DataExampleRbacTestTestAllow                        367 ± 0%
    

    基准测试前后对比自然也是支持,如benchstat old.txt new.txt,就不详述了。

    这些工具固然好,高性能还是需要 follow 一些经验法则的

    这里引用官方对于性能优化的建议如下(key-takeaways):

    • 编写策略(policy)要最大程度地减少迭代和搜索。
      • 使用的数组元素有唯一标识符时,改为唯一标识作为 key 的对象。
      • 考虑利用部分评估(partial-evaluation)以将非线性策略编译为线性策略。
    • 利用规则索引优化(rule-indexing)编写策略,以便规则索引有效。
    • 使用探查器(profiler)可帮助确定策略的哪些部分将从提高的性能中受益最大。
    • 使用基准测试工具(benchmark tools)来帮助获取真实世界的时序数据并检测策略性能变化。

    里边提到的partial-evaluationrule-indexing是保证OPA高性能的两个重要特性,感兴趣的同学可以自行查看下。

    下一篇,我们来谈谈OPA的一个重磅功能 - bundle, 一种将策略及数据进行包组织的方式,也支持丰富的管理restful api,适合分布式决策服务的构建。


    文章首发公众号:newbmiao

    推荐阅读:OPA 系列

    欢迎关注,获取及时更新内容

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3396 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 11:17 · PVG 19:17 · LAX 04:17 · JFK 07:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.