Skip to content

Support request rate limiting #201

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

Merged
merged 6 commits into from
Aug 17, 2018
Merged

Conversation

harveylowndes
Copy link
Contributor

Resolves: #108

Copy link
Contributor

@prydie prydie left a comment

Choose a reason for hiding this comment

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

Looking good bar a few minor changes 👍

@@ -40,16 +41,24 @@ type Interface interface {
Networking() NetworkingInterface
}

// OperationPollRateLimiter reader and writer.
type OperationPollRateLimiter struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

OperationPollRateLimiter implies to me that the rate limiter is only used for polling operations (e.g. polling work requests). It's used for all API requests, however. Suggest just RateLimiter.

if isWrite {
opType = "write"
}
return fmt.Errorf("Rate limited(%s) for operation: %s", opType, opName)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should use errors.Errorf to capture stack and error strings shouldn't start with a capital.

@@ -48,6 +49,11 @@ type LoadBalancerInterface interface {
}

func (c *client) GetLoadBalancer(ctx context.Context, id string) (*loadbalancer.LoadBalancer, error) {
// Read rate limiting
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably not needed. Would ditch this and similar comments.

@@ -48,6 +53,11 @@ func (c *client) GetInstance(ctx context.Context, id string) (*core.Instance, er
}

func (c *client) getInstanceByDisplayName(ctx context.Context, compartmentID, displayName string) (*core.Instance, error) {
// Read rate limiting
if !c.rateLimiter.Reader.TryAccept() {
Copy link
Contributor

Choose a reason for hiding this comment

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

As getInstanceByDisplayName (potentially) makes multiple calls to the SDK this should be within the for loop prior to the call to c.compute.ListInstances.

pkg/oci/ccm.go Outdated
@@ -73,7 +79,46 @@ func NewCloudProvider(config *Config) (cloudprovider.Interface, error) {
if err != nil {
return nil, err
}
c, err := client.New(cp)

operationPollRateLimiterRead := flowcontrol.NewFakeAlwaysRateLimiter()
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't think these two lines are required as the rate limiter isn't optional

@@ -273,14 +339,19 @@ func (c *client) AwaitWorkRequest(ctx context.Context, id string) (*loadbalancer
wr = twr
return true, nil
case loadbalancer.WorkRequestLifecycleStateFailed:
return false, errors.Errorf("WorkRequest %q failed: %s", id, twr.Message)
return false, errors.Errorf("WorkRequest %q failed: %s", id, *twr.Message)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is WorkRequest.Message a required field? If not will need to nil check.

@@ -71,6 +81,11 @@ func (c *client) GetSubnet(ctx context.Context, id string) (*core.Subnet, error)
// GetSubnetFromCacheByIP checks to see if the given IP is contained by any subnet CIDR block in the subnet cache
// If no hits were found then no subnet and no error will be returned (nil, nil)
func (c *client) GetSubnetFromCacheByIP(ip string) (*core.Subnet, error) {
// Read rate limiting
if !c.rateLimiter.Reader.TryAccept() {
Copy link
Contributor

Choose a reason for hiding this comment

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

No need to rate limit access to the local cache

@@ -46,6 +51,11 @@ func (c *client) getVNIC(ctx context.Context, id string) (*core.Vnic, error) {
}

func (c *client) GetSubnet(ctx context.Context, id string) (*core.Subnet, error) {
// Read rate limiting
if !c.rateLimiter.Reader.TryAccept() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Only need to rate limit if we get a cache miss.

@@ -61,6 +67,11 @@ func (c *client) GetLoadBalancer(ctx context.Context, id string) (*loadbalancer.
}

func (c *client) GetLoadBalancerByName(ctx context.Context, compartmentID, name string) (*loadbalancer.LoadBalancer, error) {
// Read rate limiting
if !c.rateLimiter.Reader.TryAccept() {
Copy link
Contributor

Choose a reason for hiding this comment

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

As GetLoadBalancerByName (potentially) makes multiple calls to the SDK this should be within the for loop prior to the call to c.compute.ListLoadBalancers().

@@ -259,6 +320,11 @@ func (c *client) UpdateListener(ctx context.Context, lbID, name string, details
}

func (c *client) AwaitWorkRequest(ctx context.Context, id string) (*loadbalancer.WorkRequest, error) {
// Read rate limiting
if !c.rateLimiter.Reader.TryAccept() {
Copy link
Contributor

Choose a reason for hiding this comment

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

No need to rate limit here. The rate limiting is applied in the call to c.GetWorkRequest() on a per OCI API request basis.

@harveylowndes harveylowndes force-pushed the support-request-rate-limiting branch 9 times, most recently from efcfa74 to 47dccc7 Compare May 22, 2018 13:20
@harveylowndes harveylowndes requested a review from simonlord May 22, 2018 13:22

type mockLoadBalancerClient struct{}

func TestRateLimiting(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure i see much value in this test as what's being tested is the kubernetes code from the flowcontrol pkg

pkg/oci/ccm.go Outdated
@@ -218,3 +229,39 @@ func buildConfigurationProvider(config *Config) (common.ConfigurationProvider, e
)
return cp, nil
}

// BuildRateLimiter ...
Copy link
Contributor

Choose a reason for hiding this comment

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

Could do with a better comment here

@harveylowndes harveylowndes force-pushed the support-request-rate-limiting branch from 47dccc7 to ec00172 Compare May 22, 2018 14:42
Copy link
Contributor

@prydie prydie left a comment

Choose a reason for hiding this comment

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

Some minor changes and query re constants but otherwise LGTM 👍

pkg/oci/ccm.go Outdated
@@ -43,6 +44,13 @@ import (
"github.com/oracle/oci-cloud-controller-manager/pkg/oci/util"
)

const (
//RateLimitQPSDefault sets a value for the default queries per second.
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing leading space before comment

pkg/oci/ccm.go Outdated
const (
//RateLimitQPSDefault sets a value for the default queries per second.
RateLimitQPSDefault = 1.0
//RateLimitBucketDefault sets a value for the default token bucket burst size.
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing leading space before comment

pkg/oci/ccm.go Outdated
@@ -43,6 +44,13 @@ import (
"github.com/oracle/oci-cloud-controller-manager/pkg/oci/util"
)

const (
//RateLimitQPSDefault sets a value for the default queries per second.
RateLimitQPSDefault = 1.0
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the rationale behind these constants?

pkg/oci/ccm.go Outdated

// buildNewRateLimiter builds and returns a struct containing read and write
// rate limiters. Defaults are used where no (0) value is provided.
func buildNewRateLimiter(config *RateLimiterConfig) client.RateLimiter {
Copy link
Contributor

Choose a reason for hiding this comment

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

 func newRateLimiter(config *RateLimiterConfig) client.RateLimiter

)

func TestBuildRateLimiterWithConfig(t *testing.T) {
var qpsRead float32 = 6.0
Copy link
Contributor

Choose a reason for hiding this comment

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

qpsRead := float32(6.0)

@@ -53,6 +57,9 @@ func (c *client) getInstanceByDisplayName(ctx context.Context, compartmentID, di
instances []core.Instance
)
for {
if !c.rateLimiter.Reader.TryAccept() {
return nil, RateLimitError(false, "getInstanceByDisplayName")
Copy link
Contributor

Choose a reason for hiding this comment

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

s/getInstanceByDisplayName/ListInstances/

@@ -81,6 +88,10 @@ func (c *client) getInstanceByDisplayName(ctx context.Context, compartmentID, di
}

func (c *client) listVNICAttachments(ctx context.Context, req core.ListVnicAttachmentsRequest) (core.ListVnicAttachmentsResponse, error) {
if !c.rateLimiter.Reader.TryAccept() {
return core.ListVnicAttachmentsResponse{}, RateLimitError(false, "listVNICAttachments")
Copy link
Contributor

Choose a reason for hiding this comment

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

s/listVNICAttachments/ListVnicAttachments/

@@ -63,6 +68,9 @@ func (c *client) GetLoadBalancer(ctx context.Context, id string) (*loadbalancer.
func (c *client) GetLoadBalancerByName(ctx context.Context, compartmentID, name string) (*loadbalancer.LoadBalancer, error) {
var page *string
for {
if !c.rateLimiter.Reader.TryAccept() {
return nil, RateLimitError(false, "GetLoadBalancerByName")
Copy link
Contributor

Choose a reason for hiding this comment

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

s/GetLoadBalancerByName/ListLoadBalancers/

@@ -113,6 +129,10 @@ func (c *client) DeleteLoadBalancer(ctx context.Context, id string) (string, err
}

func (c *client) GetCertificateByName(ctx context.Context, lbID, name string) (*loadbalancer.Certificate, error) {
if !c.rateLimiter.Reader.TryAccept() {
return nil, RateLimitError(false, "GetCertificateByName")
Copy link
Contributor

Choose a reason for hiding this comment

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

s/GetCertificateByName/ListCertificates/

@@ -33,6 +33,10 @@ type NetworkingInterface interface {
}

func (c *client) getVNIC(ctx context.Context, id string) (*core.Vnic, error) {
if !c.rateLimiter.Reader.TryAccept() {
return nil, RateLimitError(false, "getVNIC")
Copy link
Contributor

Choose a reason for hiding this comment

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

s/getVNIC/GetVnic/

Copy link
Contributor

@prydie prydie left a comment

Choose a reason for hiding this comment

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

One minor nit but otherwise 👍

func (c *client) getVNIC(ctx context.Context, id string) (*core.Vnic, error) {
func (c *client) GetVNIC(ctx context.Context, id string) (*core.Vnic, error) {
if !c.rateLimiter.Reader.TryAccept() {
return nil, RateLimitError(false, "getVNIC")
Copy link
Contributor

Choose a reason for hiding this comment

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

s/getVNIC/GetVNIC/

pkg/oci/ccm.go Outdated
@@ -43,6 +44,13 @@ import (
"github.com/oracle/oci-cloud-controller-manager/pkg/oci/util"
)

const (
// RateLimitQPSDefault sets a value for the default queries per second.
RateLimitQPSDefault = 1.0
Copy link
Contributor

Choose a reason for hiding this comment

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

@jhorwit2 Do you have any insight into appropriate values for these constants?

Copy link
Contributor

Choose a reason for hiding this comment

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

@harveylowndes After talking to @jhorwit2 offline it seems like a value of 20.0 should be ok here.

@prydie prydie force-pushed the support-request-rate-limiting branch from 5562f27 to 1fcffc0 Compare August 2, 2018 15:42
@harveylowndes harveylowndes force-pushed the support-request-rate-limiting branch from 1fcffc0 to 5165184 Compare August 3, 2018 10:00
@prydie prydie changed the title WIP: Support request rate limiting Support request rate limiting Aug 8, 2018
@prydie prydie force-pushed the support-request-rate-limiting branch from 5165184 to 0cad1b7 Compare August 13, 2018 09:30
@prydie prydie added this to the 0.6.0 milestone Aug 14, 2018
@prydie
Copy link
Contributor

prydie commented Aug 15, 2018

@harveylowndes Can you give this a rebase please to fix the conflicts (NOTE: you'll need to pull the branch again as I've made some modifications)?

@harveylowndes harveylowndes force-pushed the support-request-rate-limiting branch 2 times, most recently from 779711b to 237498c Compare August 15, 2018 15:06
@harveylowndes harveylowndes force-pushed the support-request-rate-limiting branch from 237498c to 2d6e127 Compare August 17, 2018 08:26
Copy link
Contributor

@prydie prydie left a comment

Choose a reason for hiding this comment

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

Couple of minor nits but otherwise LGTM 👍

pkg/oci/ccm.go Outdated
// newRateLimiter builds and returns a struct containing read and write
// rate limiters. Defaults are used where no (0) value is provided.
func newRateLimiter(config *RateLimiterConfig) client.RateLimiter {

Copy link
Contributor

Choose a reason for hiding this comment

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

\n

pkg/oci/ccm.go Outdated
config.RateLimitQPSRead,
config.RateLimitBucketRead)

glog.V(2).Infof("OCI using write rate limit configuration: QPS=%g, bucket=%d",
Copy link
Contributor

Choose a reason for hiding this comment

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

Use zap directly rather than glog

Copy link
Contributor

@prydie prydie left a comment

Choose a reason for hiding this comment

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

Nearly there!

pkg/oci/ccm.go Outdated
@@ -269,11 +267,11 @@ func newRateLimiter(config *RateLimiterConfig) client.RateLimiter {
config.RateLimitBucketWrite),
}

glog.V(2).Infof("OCI using read rate limit configuration: QPS=%g, bucket=%d",
zap.S().Infof("OCI using read rate limit configuration: QPS=%g, bucket=%d",
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't use the global logger; pass in a logger to newRateLimiter.

@harveylowndes harveylowndes force-pushed the support-request-rate-limiting branch 2 times, most recently from dd96ed9 to ab8fe53 Compare August 17, 2018 10:12
@prydie
Copy link
Contributor

prydie commented Aug 17, 2018

LGTM 👍

@owainlewis owainlewis self-assigned this Aug 17, 2018
@owainlewis owainlewis self-requested a review August 17, 2018 10:21
@@ -0,0 +1,59 @@
// Copyright 2017 Oracle and/or its affiliates. All rights reserved.
Copy link
Member

Choose a reason for hiding this comment

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

2017 => 2018

@harveylowndes harveylowndes force-pushed the support-request-rate-limiting branch from ab8fe53 to eb8da02 Compare August 17, 2018 10:28
Copy link
Contributor

@simonlord simonlord left a comment

Choose a reason for hiding this comment

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

Couple of things

pkg/oci/ccm.go Outdated
@@ -42,6 +43,13 @@ import (
"github.com/oracle/oci-cloud-controller-manager/pkg/oci/util"
)

const (
// RateLimitQPSDefault sets a value for the default queries per second.
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove comment

pkg/oci/ccm.go Outdated
@@ -42,6 +43,13 @@ import (
"github.com/oracle/oci-cloud-controller-manager/pkg/oci/util"
)

const (
// RateLimitQPSDefault sets a value for the default queries per second.
RateLimitQPSDefault = 20.0
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't need to start with a capital (which reduces req for a comment too) as i don't think it's used outside this pkg?

pkg/oci/ccm.go Outdated
const (
// RateLimitQPSDefault sets a value for the default queries per second.
RateLimitQPSDefault = 20.0
// RateLimitBucketDefault sets a value for the default token bucket burst size.
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove comment

pkg/oci/ccm.go Outdated
// RateLimitQPSDefault sets a value for the default queries per second.
RateLimitQPSDefault = 20.0
// RateLimitBucketDefault sets a value for the default token bucket burst size.
RateLimitBucketDefault = 5
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't need to start with a capital (which reduces req for a comment too) as i don't think it's used outside this pkg?

Copy link
Member

@owainlewis owainlewis left a comment

Choose a reason for hiding this comment

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

Approved for merge.

@owainlewis owainlewis merged commit 8d62bc4 into master Aug 17, 2018
@prydie prydie deleted the support-request-rate-limiting branch September 21, 2018 16:29
ayushverma14 pushed a commit to ayushverma14/oci-cloud-controller-manager that referenced this pull request Jul 18, 2022
* Support request rate limiting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants