OPA PrepareForEval 时间呈指数增长
OPA PrepareForEval time increases exponentially
我需要我的应用程序能够加载策略 (rego),然后根据定义的策略评估输入 JSON。
我在评估中错误地使用了 PrepareForEval
API 而不是加载策略 API。结果让我感到惊讶,因为每次评估后响应时间都呈指数增长,而策略保持不变。虽然在此之后,我已经意识到并更改了我的逻辑以在加载策略时调用 PrepareForEval
方法,然后将准备好的查询实例存储在我的结构实例中。但我仍然担心如果在加载策略时多次执行 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)
}
}
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
}
我需要我的应用程序能够加载策略 (rego),然后根据定义的策略评估输入 JSON。
我在评估中错误地使用了 PrepareForEval
API 而不是加载策略 API。结果让我感到惊讶,因为每次评估后响应时间都呈指数增长,而策略保持不变。虽然在此之后,我已经意识到并更改了我的逻辑以在加载策略时调用 PrepareForEval
方法,然后将准备好的查询实例存储在我的结构实例中。但我仍然担心如果在加载策略时多次执行 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)
}
}
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
}