by maoling

0. Why is quota necessary?

It is possible for clients to send/fetch very high volumes of data and thus monopolize server resources, cause network saturation and even DOS attack to server. Having quotas protects against these issues and is all the more important in large multi-tenant clusters where a small set of badly behaved clients can degrade user experience for the well behaved ones. Quota provides an isolation effect on users applications, eliminate the noisy of neighbor, avoid users to deploy multiple sets of zk cluster for every application in most general scenarios. Of course, because in the same JVM instance, this isolation provided is not as hard as the hardware/physics isolation.

1. Space Quota

We now can use quota feature to limit the the total children count or bytes under a znode. we can called this Quota type: Space Quota. (Not repeat it again here).

2. Throttle Quota

2.0 brief introduction

We also require another Quota type: Throttle Quota(or throughput Quota) which is able to limit the QPS of requests, throttle request peak/pressure and smooth request traffic. Throttle Quota can also have protective effects on the server as RequestThrottler did, and more flexible as it can be tuning during the runtime

2.1 manual

2.2 Scope

Background: Suppose that we have 26 downstream businesses(from business-A to business-Z). If latency spike happens and traffic surges, how can we detect which business is responsible for this and control this emergency situation rapidly? To meet this demand, we need to do some works to identity the client. The scope of Throttle Quota can be implemented from these two alternative dimensions: User or Client.id

2.2.1 User:

ZooKeeper doesn't have a thorough user management component. For simplification, we can take advantage of the username:password of ACL digest auth.

String auth = userName + ":" +password;
zk.addAuthInfo("digest", auth.getBytes());
2.2.2 Client.id:

client.id is a logical grouping of clients with a meaningful name chosen by the client application.
client.id are defined in the application using the client.id property. A client ID identifies an application making a request.

2.2.2.1 How to generate the client.id?
2.2.3 Hard/Soft Throttle Quota

3 Some existing designs

3.1

In the original implementation of ZOOKEEPER-1383, it counted the throughput from ServerCnxn#packetReceived based on a simple time-window approach. However it did not distinguish between read and write requests, and it's not easy and appropriate to do it at that place: ServerCnxn. It used the ServerCnxn#resetStats to split/divide time windows, it's not good for controlling the traffic more precisely in a fine-grained manner.

A Simplified request workflow:
request ---> ServerCnxn ---> RequestThrottler ---> PrepRequestProcessor --->......---> FinalRequestProcessor

3.2

In the FB's design[1], they combine with RequestThrottler based on the Rolling-window rate throttling approach. When request arrives at the RequestThrottler, asks for the RequestOracle to update/check Quotas and make a throttling decision, then pipeline requests in the RequestProcessors. more details in [1],[2]

Reference: