Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

frequency parameters traffic control #119

Conversation

louyuting
Copy link
Collaborator

Describe what this PR does / why we need it

Frequency parameters traffic control implementation.

Does this pull request fix one issue?

Describe how you did it

Supporting reject directly strategy and throttling strategy.
Using token counter to record statistics。

Describe how to verify it

Special notes for reviews

@louyuting louyuting linked an issue Apr 6, 2020 that may be closed by this pull request
@codecov-io
Copy link

codecov-io commented Apr 6, 2020

Codecov Report

Merging #119 into master will decrease coverage by 1.74%.
The diff coverage is 34.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #119      +/-   ##
==========================================
- Coverage   43.48%   41.74%   -1.75%     
==========================================
  Files          67       74       +7     
  Lines        2863     3507     +644     
==========================================
+ Hits         1245     1464     +219     
- Misses       1479     1865     +386     
- Partials      139      178      +39     
Impacted Files Coverage Δ
api/api.go 32.78% <0.00%> (-1.70%) ⬇️
core/base/result.go 38.33% <ø> (ø)
core/config/config.go 25.00% <0.00%> (ø)
core/freq_params_traffic/concurrency_stat_slot.go 0.00% <0.00%> (ø)
core/stat/base/leap_array.go 64.36% <0.00%> (ø)
util/atomic.go 58.33% <0.00%> (-25.67%) ⬇️
core/freq_params_traffic/rule_manager.go 0.72% <0.72%> (ø)
core/freq_params_traffic/rule.go 25.75% <25.75%> (ø)
core/freq_params_traffic/slot.go 34.11% <34.11%> (ø)
core/freq_params_traffic/traffic_shaping.go 43.58% <43.58%> (ø)
... and 11 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 975debd...9f00b0f. Read the comment docs.

@sczyh30 sczyh30 added kind/feature Category issues or PRs related to feature request to-review PRs to review labels Apr 7, 2020
@louyuting louyuting force-pushed the frequent-parameters-flow-control-implementation branch 2 times, most recently from 9b64632 to 14a48a7 Compare April 17, 2020 11:47
@louyuting louyuting requested a review from sczyh30 April 17, 2020 11:48
callbackUpdateMux = new(sync.RWMutex)
)

type StatSlotEntryCallback interface {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the stat slot callback is not needed? Just make it as another StatSlot and add it to slot chain is okay :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a new StatSlot to record the concurrency statistic seems make more sense. I will reimplement related logic.

// ruleTokenCounter record the number of token of value
ruleTokenCounter cache.ConcurrentCounterCache
// goroutineCounter record the number of goroutine of value
goroutineCounter cache.ConcurrentCounterCache
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about concurrencyCounter or something else (as the counter indicates concurrency actually)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense

type ControlStrategy int8

const (
RejectFaster ControlStrategy = iota
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just Reject is enough?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to express the meaning of quick and direct fail.
”Reject“ may be enough.


import "strconv"

type ControlStrategy int8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep the name consistent with that in FlowRule?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's ok. Keep the name convention.


type SpecificValue struct {
ValType Kind
ValueStr string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep the naming consistent? (both val or value)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay

QPS
)

type Kind int
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term "kind" has different meanings in type system. Maybe we could use ParamType or other concrete name?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here i refer to the data type definition of go standard reflect package.
https://github.com/golang/go/blob/98d20fb23551a7ab900fcfe9d25fd9cb6a98a07f/src/reflect/type.go#L230
I think keep name consistent with standard package is ok.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's okay, but just Kind may be too generic. Maybe ParamKind or other concrete?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ParamKind is Okay.


for _, tc := range tcs {
if tc == nil {
logger.Warnf("Nil traffic controller was found, res: %s", res)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may yield a large number of logs. As this is not expected as usual, maybe we could make it "debug" level?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense.

logger.Warnf("The TrafficShapingController's paramIndex(%d) less than 0.", idx)
}
if len(args) <= idx {
logger.Warnf("The index of rule is not existed in args. The TrafficShapingController's paramIndex is %d, args: %+v, tc: %+v", idx, args, tc)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto for "debug" level

continue
}
idx := tc.getParamIndex()
if idx < 0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could support reversed index here. For example, -1 means the last one. This could be useful when the length of parameter list is not fixed.

awaitTime := expectedTime - currentTimeInMs
if awaitTime > 0 {
atomic.StoreInt64(lastPassTimePtr, expectedTime)
time.Sleep(time.Duration(awaitTime) * time.Millisecond)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's better to use NewTokenResultShouldWait instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay

logger.Warnf("The TrafficShapingController's paramIndex(%d) less than 0.", idx)
}
if len(args) <= idx {
logger.Warnf("The index of rule is not existed in args. The TrafficShapingController's paramIndex is %d, args: %+v, tc: %+v", idx, args, tc)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto for logging level. Also typo: is not existed -> does not exist

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay

@louyuting louyuting force-pushed the frequent-parameters-flow-control-implementation branch from 3bdd464 to 5fab2ef Compare May 8, 2020 17:07
return nil
}
switch arg.(type) {
case int:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also support bool/float32/float64 here?

@louyuting louyuting force-pushed the frequent-parameters-flow-control-implementation branch from 86ee5dc to 1974b3e Compare May 21, 2020 13:46
@codecov-commenter
Copy link

codecov-commenter commented May 21, 2020

Codecov Report

Merging #119 into master will increase coverage by 2.12%.
The diff coverage is 53.18%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #119      +/-   ##
==========================================
+ Coverage   40.77%   42.90%   +2.12%     
==========================================
  Files          68       75       +7     
  Lines        3279     3951     +672     
==========================================
+ Hits         1337     1695     +358     
- Misses       1810     2065     +255     
- Partials      132      191      +59     
Impacted Files Coverage Δ
api/api.go 30.50% <0.00%> (-1.64%) ⬇️
core/base/result.go 29.35% <ø> (ø)
core/config/config.go 25.00% <0.00%> (ø)
core/freq_params_traffic/concurrency_stat_slot.go 0.00% <0.00%> (ø)
core/stat/base/leap_array.go 57.14% <0.00%> (ø)
util/atomic.go 58.33% <0.00%> (-25.67%) ⬇️
core/freq_params_traffic/slot.go 32.95% <32.95%> (ø)
core/freq_params_traffic/rule_manager.go 53.12% <53.12%> (ø)
core/freq_params_traffic/cache/lru.go 53.77% <53.77%> (ø)
core/freq_params_traffic/rule.go 58.75% <58.75%> (ø)
... and 11 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 46b892a...43968c8. Read the comment docs.

@louyuting louyuting force-pushed the frequent-parameters-flow-control-implementation branch from 1974b3e to aa358bc Compare May 23, 2020 16:02
@louyuting louyuting requested a review from sczyh30 May 23, 2020 16:08
}

func newBaseTrafficShapingControllerWithMetric(r *Rule, metric *ParamsMetric) *baseTrafficShapingController {
size := int(math.Min(float64(ParamsMaxCapacity), float64(ParamsCapacityBase*r.DurationInSec)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about making the cache size as an attribute of the param flow rule?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe an optional attribute make sense.

@louyuting louyuting requested a review from sczyh30 May 27, 2020 14:16
@sczyh30
Copy link
Member

sczyh30 commented Jun 3, 2020

I've been testing with the demo and found the pass count flaky like this (see the attachment):

sentinel-go-demo-local-metrics.log

Rule:

{
	Resource:          "test",
	MetricType:        freq_params_traffic.QPS,
	Behavior:          freq_params_traffic.Reject,
	ParamIndex:        0,
	Threshold:         100,
	MaxQueueingTimeMs: 0,
	ParamsMaxCapacity: 2,
	DurationInSec:     1,
	SpecificItems:     make(map[freq_params_traffic.SpecificValue]int64),
}

Demo:

// Usually, the total pass QPS is expected to be 200 (two parameters, 100 respectively).
for i := 0; i < 8; i++ {
	go func() {
		for {
			e, b := sentinel.Entry(Resource, sentinel.WithSlotChain(sc), sentinel.WithArgs(true, rand.Int()%3000, uuid.New().String(), uuid.New().String()))
			if b != nil {
				// Blocked. We could get the block reason from the BlockError.
				time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)
			} else {
				// Passed, wrap the logic here.
				time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)
				// Be sure the entry is exited finally.
				e.Exit()
			}
		}
	}()
}

for {
	e, b := sentinel.Entry(Resource, sentinel.WithSlotChain(sc), sentinel.WithArgs(false, rand.Int()%3000, uuid.New().String(), uuid.New().String()))
	if b != nil {
		time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)
	} else {
		// Passed, wrap the logic here.
		time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)

		// Be sure the entry is exited finally.
		e.Exit()
	}
}

Any ideas about it?

Copy link
Member

@sczyh30 sczyh30 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, we may improve this in upcoming pull requests

@sczyh30 sczyh30 removed the to-review PRs to review label Jun 5, 2020
@sczyh30 sczyh30 merged commit 03d6c0d into alibaba:master Jun 5, 2020
@sczyh30
Copy link
Member

sczyh30 commented Jun 5, 2020

Fabulous work. Thanks!

@sczyh30 sczyh30 added the size/XXL Indicate a PR that changes 1000+ lines. label Jun 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/feature Category issues or PRs related to feature request size/XXL Indicate a PR that changes 1000+ lines.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

"Frequent" parameter flow control
4 participants