LGTM in terms of RPC separation and the new SubscriptionId to detect target
metric change on the server side.

On Tue, Sep 14, 2021 at 12:48 AM Magnus Edenhill <mag...@edenhill.se> wrote:

> Thanks for your feedback Colin, see my updated proposal below.
>
>
> Den tors 22 juli 2021 kl 03:17 skrev Colin McCabe <cmcc...@apache.org>:
>
> > On Tue, Jun 29, 2021, at 07:22, Magnus Edenhill wrote:
> > > Den tors 17 juni 2021 kl 00:52 skrev Colin McCabe <cmcc...@apache.org
> >:
> > > > A few critiques:
> > > >
> > > > - As I wrote above, I think this could benefit a lot by being split
> > into
> > > > several RPCs. A registration RPC, a report RPC, and an unregister RPC
> > seem
> > > > like logical choices.
> > > >
> > >
> > > Responded to this in your previous mail, but in short I think a single
> > > request is sufficient and keeps the implementation complexity / state
> > down.
> > >
> >
> > Hi Magnus,
> >
> > I still suspect that trying to do everything with a single RPC is more
> > complex than using multiple RPCs.
> >
> > Can you go into more detail about how the client learns what metrics it
> > should send? This was the purpose of the "registration" step in my scheme
> > above.
> >
> > It seems quite awkward to combine an RPC for reporting metrics with and
> > RPC for finding out what metrics are configured to be reported. For
> > example, how would you build a tool to check what metrics are configured
> to
> > be reported? Does the tool have to report fake metrics, just because
> > there's no other way to get back that information? Seems wrong. (It would
> > be a bit like combining createTopics and listTopics for "simplicity")
> >
>
>
>
> Splitting up the API into separate data and control requests makes sense.
> With a split we would have one API for querying the broker for configured
> metrics subscriptions,
> and one API for pushing the collected metrics to the broker.
>
> A mechanism is still needed to notify the client when the subscription is
> changed;
> I’ve added a SubscriptionId for this purpose (which could be a checksum of
> the configured metrics subscription), this id is sent to the client along
> with the metrics subscription, and the client sends it back to the broker
> when pushing metrics. If the broker finds the pushed subscription id to
> differ from what is expected it will return an error to the client, which
> triggers the client to retrieve the new subscribed metrics and an updated
> subscription id. The generation of the subscriptionId is opaque to the
> client.
>
>
> Something like this:
>
> // Get the configured metrics subscription.
> GetTelemetrySubscriptionsRequest {
>    StrNull  ClientInstanceId  // Null on first invocation to retrieve a
> newly generated instance id from the broker.
> }
>
> GetTelemetrySubscriptionsResponse {
>   Int16  ErrorCode
>   Int32  SubscriptionId   // This is used for comparison in
> PushTelemetryRequest. Could be a crc32 of the subscription.
>   Str    ClientInstanceId
>   Int8   AcceptedContentTypes
>   Array  SubscribedMetrics[] {
>       String MetricsPrefix
>       Int32  IntervalMs
>   }
> }
>
>
> The ContentType is a bitmask in this new proposal, high bits indicate
> compression:
>   0x01   OTLPv08
>   0x10   GZIP
>   0x40   ZSTD
>   0x80   LZ4
>
>
> // Push metrics
> PushTelemetryRequest {
>    Str    ClientInstanceId
>    Int32  SubscriptionId    // The collected metrics in this request are
> based on the subscription with this Id.
>    Int8   ContentType       // E.g., OTLPv08|ZSTD
>    Bool   Terminating
>    Binary Metrics
> }
>
>
> PushTelemetryResponse {
>    Int32 ThrottleTime
>    Int16 ErrorCode
> }
>
>
> An example run:
>
> 1. Client instance starts, connects to broker.
> 2. > GetTelemetrySubscriptionsRequest{ ClientInstanceId=Null } // Requests
> an instance id and the subscribed metrics.
> 3. < GetTelemetrySubscriptionsResponse{
>       ErrorCode = 0,
>       SubscriptionId = 0x234adf34,
>       ClientInstanceId = f00d-feed-deff-ceff-ffff-…,
>       AcceptedContentTypes = OTLPv08|ZSTD|LZ4,
>       SubscribeddMetrics[] = {
>          { “client.producer.tx.”, 60000 },
>          { “client.memory.rss”, 900000 },
>       }
>    }
> 4. Client updates its metrics subscription, next push to fire in 60
> seconds.
> 5. 60 seconds passes
> 6. > PushTelemetryRequest{
>        ClientInstanceId = f00d-feed-deff-ceff-ffff-….,
>        SubscriptionId = 0x234adf34,
>        ContentType = OTLPv8|ZSTD,
>        Terminating = False,
>        Metrics = …// zstd-compressed OTLPv08-protobuf-serialized metrics
>   }
> 7. < PushTelemetryResponse{ 0, NO_ERROR }
> 8. 60 seconds passes
> 9. > PushTelemetryRequest…
> …
> 56. The operator changes the configured metrics subscriptions (through
> Admin API).
> 57. > PushTelemetryRequest{ .. SubscriptionId = 0x234adf34 .. }
> 58. The subscriptionId no longer matches since the subscription has been
> updated, broker responds with an error:
> 59. < PushTelemetryResponse{ 0,   ERR_INVALID_SUBSCRIPTION_ID }
> 60. The error triggers the client to request the subscriptions again.
> 61. > GetTelemetrySubscriptionsRequest{..}
> 62. < GetTelemetrySubscriptionsResponse { .. SubscriptionId = 0x777772211,
> SubscribedMetrics[] = .. }
> 63. Client update its subscription and continues to push metrics
> accordingly.
> …
>
>
> If the broker connection goes down or the connection is to be used for
> other purposes (e.g., blocking FetchRequests), the client will send
> PushTelemetryRequests to any other broker in the cluster, using the same
> ClientInstanceId and SubscriptionId as received in the latest
> GetTelemetrySubscriptionsResponse.
>
> While the subscriptionId may change during the lifetime of the client
> instance (when metric subscriptions are updated), the ClientInstanceId is
> only acquired once and must not change (as it is used to identify the
> unique client instance).
>
>
> >
> > > > - I don't think the client should be able to choose its own UUID.
> This
> > > > adds complexity and introduces a chance that clients will choose an
> ID
> > that
> > > > is not unique. We already have an ID that the client itself supplies
> > > > (clientID) so there is no need to introduce another such ID.
> > > >
> > >
> > > The CLIENT_INSTANCE_ID (which is a combination of the client.id and a
> > UUID)
> > > is actually generated by the receiving broker on first contact.
> > > The need for a new unique semi-random id is outlined in the KIP, but in
> > > short; the client.id is not unique, and we need something unique that
> > still
> > > is prefix-matchable to the client.id so that we can add subscriptions
> > > either using prefix-matching of just the client.id (which may match
> one
> > or
> > > more client instances), and exact matching which will match a one
> > specific
> > > client instance.
> >
> > Hmm... the client id is already sent in every RPC as part of the header.
> > It's not necessary to send it again as part of one of the other RPC
> fields,
> > right?
> >
> > More generally, why does the client instance ID need to be
> > prefix-matchable? That seems like an implementation detail of the metrics
> > collection system used on the broker side. Maybe someone wants to group
> by
> > things other than client IDs -- perhaps client versions, for instance. By
> > the same argument, we should put the client version string in the client
> > instance ID, since someone might want to group by that. Or maybe we
> should
> > include the hostname, and the IP, and, and, and.... You see the issue
> here.
> > I think we shouldn't get involved in this kind of decision -- if we just
> > pass a UUID, the broker-side software can group it or prefix it however
> it
> > wants internally.
> >
>
> Yes, I agree, other selectors will indeed be needed eventually.
> I'll remove the client.id from the CLIENT_INSTANCE_ID and only keep the
> UUID part.
> My assumption is that the set of subscribed metrics prefixes throughout a
> cluster will be quite small initially, so maybe we could leave fine-grained
> selectors out of this proposal
> and address it later when an actual need arises (maybe ACLs can be used for
> selector matching).
> And there is no harm for a client in having a metrics subscription with
> metrics it does not provide, e.g.,  including the consumer metrics for a
> producer, and vice versa, it will just be ignored by the client
> if it doesn't match a metrics prefix it can provide.
>
> What we do want though is ability to single out a specific client instance
> to give it a more fine-grained subscription for troubleshooting, and
> we can do that with the current proposal with matching solely on the
> CLIENT_INSTANCE_ID.
> In other words; all clients will have the same standard metrics
> subscription, but specific client instances can have alternate
> subscriptions.
>
>
> > > - In general the schema seems to have a bad case of string-itis. UUID,
> > > > content type, and requested metrics are all strings. Since these
> > messages
> > > > will be sent very frequently, it's quite costly to use strings for
> all
> > > > these things. We have a type for UUID, which uses 16 bytes -- let's
> use
> > > > that type for client instance ID, rather than a string which will be
> > much
> > > > larger. Also, since we already send clientID in the message header,
> > there
> > > > is no need to include it again in the instance ID.
> > > >
> > >
> > > As explained above we need the client.id in the CLIENT_INSTANCE_ID.
> And
> > I
> > > don't think the overhead of this one string per request is going to be
> > much
> > > of an issue,
> > > typical metric push intervals are probably in the >60s range.
> > > If this becomes a problem we could use a per-connection identifier that
> > the
> > > broker translates to the client instance id before pushing metrics
> > upwards
> > > in the system.
> > >
> >
> > This is actually an interesting design question -- why not use a
> > per-TCP-connection identifier, rather than a per-client-instance
> > identifier? If we are grouping by other things anyway (clientID,
> principal,
> > etc.) on the server side, do we need to maintain a per-process identifier
> > rather than a per-connection one?
> >
>
>
> The metrics collector/tsdb/whatever will need to identify a single client
> instance, regardless of which broker received the metrics.
> The chapter on CLIENT_INSTANCE_ID motivates why we need a unique
> identifier, basically because neither clientID, principal or remote
> address:port, etc, can be
> used to identify a single client instance.
>
>
>
>
> > >
> > > > - I think it would also be nice to have an enum or something for
> > > > AcceptedContentTypes, RequestedMetrics, etc. We know that new
> > additions to
> > > > these categories will require KIPs, so it should be straightforward
> > for the
> > > > project to just have an enum that allows us to communicate these as
> > ints.
> > > >
> > >
> > > I'm thinking this might be overly constraining. The broker doesn't
> parse
> > or
> > > handle the received metrics data itself but just pushes it to the
> metrics
> > > plugin, using an enum would require a KIP and broker upgrade if the
> > metrics plugin
> > > supports a newer version of OTLP.
> > > It is probably better if we don't strictly control the metric format
> > itself.
> > >
> >
> > Unfortunately, we have to strictly control the metrics format, because
> > otherwise clients can't implement it. I agree that we don't need to
> specify
> > how the broker-side code works, since that is pluggable. It's also
> > reasonable for the clients to have pluggable extensions as well, but this
> > KIP won't be of much use if we don't at least define a basic set of
> metrics
> > that most clients can understand how to send. The open source clients
> will
> > not implement anything more than what is specified in the KIP (or at
> least
> > the AK one won't...)
> >
>
> Makes sense, in the updated proposal above I changed ContentType to a
> bitmask.
>
>
> >
> > >
> > >
> > > > - Can you talk about whether you are adding any new library
> > dependencies
> > > > to the Kafka client? It seems like you'd want to add opencensus /
> > > > opentelemetry, if we are using that format here.
> > > >
> > >
> > > Yeah, as we get closer to concensus more implementation specific
> details
> > > will be added to the KIP.
> > >
> >
> > I'm not sure if OpenCensus adds any value to this KIP, to be honest.
> Their
> > primary focus was never on the format of the data being sent (in fact,
> the
> > last time they checked, they left the format up to each OpenCensus
> > implementation). That may have changed, but I think it still has limited
> > usefulness to us, since we have our own format which we have to use
> anyway.
> >
>
> Oh, I meant concensus as in kafka-dev agreement :)
>
> Feng is looking into the implementation details of the Java client and will
> update the KIP with regards to dependencies.
>
>
>
> >
> > >
> > > >
> > > > - Standard client resource labels: can we send these only in the
> > > > registration RPC?
> > > >
> > >
> > > These labels are part of the serialized OTLP data, which means it would
> > > need to be unpacked and repacked (including compression) by the broker
> > (or
> > > metrics plugin), which I believe is more costly than sending them for
> > each request.
> > >
> >
> > Hmm, that data is about 10 fields, most of which are strings. It
> certainly
> > adds a lot of overhead to resend it each time.
> >
> > I don't follow the comment about unpacking and repacking -- since the
> > client registered with the broker it already knows all this information,
> so
> > there's nothing to unpack or repack, except from memory. If it's more
> > convenient to serialize it once rather than multiple times, that is an
> > implementation detail of the broker side plugin, which we are not
> > specifying here anyway.
> >
>
> The current proposal is pretty much stateless on the broker, it does not
> need to hold any state for a client (instance), and no state
> synchronization is needed
> between brokers in the cluster, which allows a client to seamlessly send
> metrics to any broker it wants and keeps the API overhead down (no need to
> re-register when
> switching brokers for instance).
>
> We could remove the labels that are already available to the broker on a
> per-request basis or that it already maintains state for:
>  - client_id
>  - client_instance_id
>  - client_software_*
>
> Leaving the following to still be included:
>  - group_id
>  - group_instance_id
>  - transactional_id
>   etc..
>
> What do you think of that?
>
>
> Thanks,
> Magnus
>
>
>
> >
> > best,
> > Colin
> >
> > > Thanks,
> > > Magnus
> > >
> > > >
> > > >
> > >
> >
>


-- 
Best,
Feng

Reply via email to