You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 26 Next »

Status

Current state: Draft

Discussion thread: TODO

JIRA: TODO

Please keep the discussion on the mailing list rather than commenting on the wiki (wiki discussions get unwieldy fast).

Motivation

Quota management via Admin Client has gone through a couple drafts of proposals (KIP-248, KIP-422). While improvements have been made to the Admin interface for configuration handling, fitting quotas into the API would be restrictive because they don't fit the natural key-value pairing. Therefore, it'd be beneficial to have a quota-native API for administrating quotas, which would offer an intuitive and less error-prone interface, convey additional useful information beyond what the configuration APIs could provide, and provide for future extensibility as quotas types are added or evolved.

Background

Quotas are defined in terms of a user and client ID, where the user acts as a specific opaque principal, and the client ID as a more generic group identifier.

When setting quotas, an administrator has flexibility in how it specifies the user and client ID for which the quota applies to, where the user and client ID may be named, indicated as the default, or omitted entirely. This creates a hierarchy structure for which quotas apply, where the most specific, defined quota will be matched to a request's user and client ID.

As represented by the current ZK node structure, the order in which quotas are matched are as follows. Note <user> is a specified user name, <client-id> is a specified client ID, and <default> is a special default user/client ID represented as the literal string "<default>".

        /config/users/<user>/clients/<client-id>
        /config/users/<user>/clients/<default>
        /config/users/<user>
        /config/users/<default>/clients/<client-id>
        /config/users/<default>/clients/<default>
        /config/users/<default>
        /config/clients/<client-id>
        /config/clients/<default>

As such, reasoning around quotas can be complex, as it's not immediately obvious which quotas may apply to a given user and/or client ID. Providing descriptive information is a goal of this KIP.

Public Interfaces

Common Types

    /**
     * Represents the default name for an entity, i.e. the entity that's matched
     * when an exact match isn't found.
     */
    public final static String QUOTA_ENTITY_DEFAULT = // implementation defined

    /**
     * Describes an entity type.
     */
    public enum QuotaEntityType {
        USER,        // The user principal.
        CLIENT_ID,   // The client ID.

        // Note others may be added in the future.
    }

    /**
     * Describes a fully-qualified entity.
     */
    public class QuotaEntity {
        /**
         * `entries` describes the fully-qualified entity. The key is a QuotaEntityType string, however
         * there may also exist keys that are not enumerated by QuotaEntityType that still apply, e.g.
         * the server may internally associate another type. It's necessary to return all quota types
         * because quota values for these types may influence the effective quota value. However,
         * altering a quota, any types that aren't specified should be able to be inferred by the
         * server, otherwise an error is returned.
         *
         * For example, {("CLIENT_ID" -> "test-client"),
         *               ("USER" -> "test-user"),
         *               ("GROUP" -> "internal-group")}.
         */
        public QuotaEntity(Map<String, String> entries);

        public Map<String, String> entries();
    }

    /**
     * The quota types.
     */
    public enum QuotaType {
        CONSUMER_BYTE_RATE,
        PRODUCER_BYTE_RATE,
        REQUEST_PERCENTAGE,

        // Note others may be added in the future.
    }

    /**
     * The units for a quota value. Note there may be multiple units for a given quota type
     * that influences quota behavior.
     */
    public enum QuotaUnits {
        RATE_BPS,

        // Note others may be added in the future, e.g. RATE_BPS_PER_BROKER, SHARES.
    }

    /**
     * Describes a quota key.
     */
    public class QuotaKey {
        /**
         * @param type the quota type
         * @param units the units for the quota type
         */
       public QuotaKey(QuotaType type, QuotaUnits units);

       public QuotaType type();
       public QuotaUnits units();
    }

DescribeQuotas

    public class QuotaFilter {
        public enum Rule {
            EXACT,    // exact name match
            NOT,      // matches all non-matching names
            PREFIX,   // matches all names with the given prefix

            // Note others may be added in the future.
        }

       /**
        * A filtering rule to be applied.
        *
        * @param entity the entity the rule applies to
        * @param rule the rule to apply
        * @param match the non-null string that's applied by the rule
        */
       public QuotaFilter(QuotaEntity entity, Rule rule, String match);

       public QuotaEntity entity();
       public Rule rule();
       public String match();
    }

    public class DescribeQuotasOptions {
        // Default.
    }

    public class DescribeQuotasResult {
        /**
         * Maps an entity to its configured quota value(s). Note if no value is defined for a quota
         * type for that entity's config, then it is not included in the resulting value map.
         *
         * @return the collection of entities that matched the filter
         */
        KafkaFuture<Map<QuotaEntity, Map<QuotaKey, Double>>> entities();
    }

    public interface Admin extends AutoCloseable {
        /**
         * Describes all entities matching all provided filters (logical AND) that have at least one
         * quota value defined.
         *
         * @param filters filtering rules to apply to matching entities
         * @param options the options to use
         * @return result containing all matching entities
         */
        DescribeQuotasResult describeQuotas(Collection<QuotaFilter> filters, DescribeQuotasOptions options);
    }

DescribeEffectiveQuotas

    public class DescribeEffectiveQuotasOptions {
        // Whether to include the list of overridden values for every quota type in the result.
        //
        // Default: false.
        DescribeQuotasOptions setOmitOverriddenValues(boolean omitOverriddenValues);
    }

    public class DescribeEffectiveQuotasResult {
        /**
         * Information about a specific quota configuration entry.
         */
        public class Entry {
            /**
             * @param source the entity source for the value
             * @param value the non-null value
             */
            public Entry(QuotaEntity source, Double value);

            public QuotaEntity source();
            public Double value();
        }

        /**
         * Information about the value for a quota type.
         */
        public class Value {
            /**
             * @param entry the quota entry
             * @param overriddenEntries all values that are overridden due to being lower in
             *                          specificity, or null if not requested
             */
            public Value(Entry entry, List<Entry> overriddenEntries);

            public Entry entry();
            public List<Entry> overriddenEntries();
        }

        /**
         * Maps a quota type to its configuration.
         */
        public Map<QuotaEntity, KafkaFuture<Map<QuotaKey, Value>>> config();
    }

    public interface Admin extends AutoCloseable {
        /**
         * Describes the effective quotas for the provided entities.
         *
         * @param entities the entities to describe the effective quotas for
         * @param options the options to use
         * @return the effective quotas for the entities
         */
        DescribeEffectiveQuotasResult describeEffectiveQuotas(Collection<QuotaEntity> entities,
                                                              DescribeEffectiveQuotasOptions options);
    }

AlterQuotas

    public class AlterQuotasEntry {
        public class Op {
            /**
             * @param key the quota type and units to alter
             * @param value if set then the existing value is updated,
             *              otherwise if null, the existing value is cleared
             */
            public Op(QuotaKey key, Double value);

            public QuotaKey key();
            public Double value();
        }

        /**
         * @param entity the entity whose config will be modified
         * @param ops the alteration to perform - if value is set, then the existing value is updated,
         *            otherwise if null, the existing value is cleared
         */
        public AlterQuotasEntry(QuotaEntity entity, Collection<Op> ops);

        public QuotaEntity entity();
        public Collection<Ops> ops();
    }

    public class AlterQuotasOptions {
        // Default.
    }

    public class AlterQuotasResult {
        /**
         * @return map of a quota entity update to its future
         */
        public Map<QuotaEntity, KafkaFuture<Void>> futures();
    }

    public interface Admin extends AutoCloseable {
        /**
         * Alters the quotas as specified for the entries.
         *
         * @param alterations the alterations to perform
         * @return the result of the alterations
         */
        AlterQuotasResult alterQuotas(Collection<AlterQuotasEntry> entries, AlterQuotasOptions options);
    }


Proposed Changes

TODO: Wire protocol.

TODO: ConfigCommand changes.

Compatibility, Deprecation, and Migration Plan

All changes would be forward-compatible, and no migration plan is necessary. It's outside the scope of this KIP to deprecate any functionality.

Rejected Alternatives

TODO



  • No labels