【问题标题】:OPA PrepareForEval time increases exponentiallyOPA PrepareForEval 时间呈指数增长
【发布时间】:2020-06-22 09:33:35
【问题描述】:

我需要我的应用程序能够加载策略 (rego),然后根据定义的策略评估输入 JSON。

我在评估 API 中错误地使用了 PrepareForEval,而不是加载策略 API。这个结果让我感到惊讶,因为每次评估后响应时间都呈指数级增长,而策略却保持不变。虽然在此之后,我已经意识到并改变了我的逻辑,在加载策略时调用PrepareForEval 方法,然后将准备好的查询实例存储在我的结构实例中。但是我仍然担心如果 prepare 方法在加载策略时被多次执行,那么它仍然会成为一项昂贵的操作。

所以,最好指出使用 prepare 方法的正确方法。

示例代码:

// My provider
func init() {
  cachedRego := rego.New(rego.Query("data.report"))
}

// My load policy method
func loadPolicy(ctx context.Context, filename, regoPolicy string) {
  mod, err := ast.ParseModule(filename, regoPolicy)
  rego.ParsedModule(mod)(cachedRego)
}

// My evaluate method
func eval(ctx context.Context, input interface{}) {
  // after loading my policies, the following call took 1s, 2s, 5s, 10s,... respectively on eval calls
  preparedQuery, _ := cachedRego.PrepareForEval(ctx) // <- I've moved this to my load policy method and cached preparedQuery

  // this doesn’t take much time
  rs, _ := preparedQuery.Eval(ctx, rego.EvalInput(input))
}

// My use case
func main() {
  // load policies and evaluate inputs
  for _, p := range policySet1 {
    loadPolicy(context.Background(), p.filename, p.regoPolicy)
  }

  for _, inp := range inputSet1 {
    eval(context.Background(), inp)
  }


  // load more policies to the earlier set and evaluate another input set
  for _, p := range policySet2 {
    loadPolicy(context.Background(), p.filename, p.regoPolicy)
  }

  for _, inp := range inputSet2 {
    eval(context.Background(), inp)
  }
}

【问题讨论】:

    标签: open-policy-agent rego


    【解决方案1】:

    TLDR;这可能不是这个问题的正确位置。如果您发现自己认为错误的行为,请在 GitHub 上提出问题。

    要回答有关如何正确准备查询的问题,您的主要功能应该(至少)如下所示:

    func main() {
      pq1 := loadPolicies(policySet1)
      
      for _, inp := range inputSet1 {
        eval(pq1, inp)
      }
    
      pq2 := loadPolicies(policySet2)
     
      for _, inp := range inputSet2 {
        eval(pq2, inp)
      }
    }
    

    对于上述示例,实现loadPolicies 的最简单方法是:

    func loadPolicies(policySet) {
    
      opts := []func(*rego.Rego){}
    
      // setup prepared query. load all modules.
      for _, p := range policySet {
        opts = append(opts, rego.Module(p.filename, p.regoPolicy))
      }
    
      // create new prepared query
      return rego.New(rego.Query("data.report"), opts...).PrepareForEval()
    }
    

    那么你的 eval 函数就变成了:

    func eval(pq, inp) {
       rs, err := pq.Eval(rego.EvalInput(inp))
       // handle err
       // interpret rs
    }
    

    【讨论】:

    • 谢谢,我会在 GitHub 上提出问题。现在,我将尝试在完整的策略集上准备一次。虽然我需要在现有实例中动态添加策略的能力。但我想正如你所指出的那样,重新启动 Rego 实例可能会更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多