Nikolay, > Add ability to sent custom affinity class name. Can you please elaborate? What is sent where?
> If `partitionAwarenessEnabled=true` but custom affinity can’t be instantiated on the client - throw an exception Unfortunately, this is a breaking change. Currently this scenario works without errors - uses default socket for custom affinity caches. On Fri, Jul 8, 2022 at 3:23 PM Николай Ижиков <nizhi...@apache.org> wrote: > Hello, Pavel. > > I support your proposal to transparently create custom AffinityMapper > based on server node classname, in general. > Partition Awareness crucial point for a thin client performance so It > should be absolutely clear for a user - PA works correctly or not. > > So, I think, we should implement the following: > > 0. Add ability to sent custom affinity class name. > 1. If `partitionAwarenessEnabled=true` but custom affinity can’t be > instantiated on the client - throw an exception. > > WDYT? > > > 8 июля 2022 г., в 08:37, Pavel Tupitsyn <ptupit...@apache.org> > написал(а): > > > > To clarify: you can use a different AffinityFunction implementation on > the > > client side. It just has to map to the same binary typeId. > > Even if there is a legacy setup with AffinityKeyMapper on servers, you > can > > craft an AffinityFunction for the client that achieves correct behavior. > > So I believe this should cover any use case. > > > > On Thu, Jul 7, 2022 at 10:36 PM Pavel Tupitsyn <ptupit...@apache.org> > wrote: > > > >> AffinityKeyMapper is just a subset of AffinityFunction, isn't it? > >> So by supporting AffinityFunction we cover all AffinityKeyMapper use > cases. > >> > >> > >>> managing the classpath, a user should always keep in mind it > >> I don't consider this a problem. This is how Java works, what can we do? > >> You can also stick the class into BinaryConfiguration on the client to > >> make it explicit and make sure it is loaded. > >> > >>> it still possible having user bad implementations of AffinityFunction > >> that can't be easily instantiated; > >> It is also possible to provide a bad implementation of ToIntFunction, no > >> difference. > >> > >>> a question - what we should do in case of class instantiating loading > >> fails? > >> Currently we don't fail on custom affinity, right? So we should keep > this > >> behavior. Print a warning. > >> > >> On Thu, Jul 7, 2022 at 10:27 PM Maxim Muzafarov <mmu...@apache.org> > wrote: > >> > >>> Pavel, > >>> > >>> > >>> Yes, you're right that AffinityKeyMapper is deprecated, this is sad to > >>> say but it still used. > >>> > >>> Let me describe the cases in more detail. In general, we have > >>> customers which are using: > >>> > >>> 1. an own custom AffinityFunction; > >>> 2. the default RendezvousAffinityFunction + an own deprecated > >>> AffinityKeyMapper; > >>> 3. an own custom AffinityFunction + an own deprecated > >>> AffinityKeyMapper (I doubt about this case); > >>> > >>> I'd like to provide a general solution that solves all the cases > >>> mentioned above, thus we can't discuss only AffinityFunction. It > >>> doesn't fit the initial goals. > >>> > >>> > >>>> Can you please clarify the "tricky" part? > >>> > >>> Yes, from my point of view the tricky part here is: > >>> > >>> - managing the classpath, a user should always keep in mind it; > >>> - it still possible having user bad implementations of > >>> AffinityFunction that can't be easily instantiated; > >>> - a question - what we should do in case of class instantiating > >>> loading fails? drop the client, print the warn or do nothing. These > >>> solutions have a different impact on a production environment and user > >>> may have different expectations on that; > >>> > >>> > >>> I'm not saying that solution you suggested is bad, it just has some > >>> drawbacks (like other solutions) and doesn't solves all the cases if > >>> we're not instantiating a deprecated AffinityKeyMapper (which looks a > >>> bit ugly for me too). > >>> > >>> > >>> Actually, we are not limited with setting/instantiating > >>> AffinityFunction. We can provide for a user a control on which channel > >>> (node) a particular cache request will be executed (this thing also > >>> have a drawback - a transactional operation cannot be executed on an > >>> arbitrary node, it should be executed on node it's started). > >>> > >>> On Thu, 7 Jul 2022 at 21:41, Pavel Tupitsyn <ptupit...@apache.org> > wrote: > >>>> > >>>>> AffinityKeyMapper (it will be required too) > >>>> It is deprecated. We should not add any functionality on top of > >>> deprecated > >>>> stuff. > >>>> Let's discuss only AffinityFunction. > >>>> > >>>>> this approach requires of these classes to be present on a thin > client > >>>> side and it can be tricky > >>>> Any of the approaches discussed above requires some additional logic > to > >>> be > >>>> present on the client. > >>>> Can you please clarify the "tricky" part? > >>>> > >>>> All you need is to provide AffinityFunction implementation with a > proper > >>>> class name > >>>> (or even use nameMapper/idMapper to map to a different name), it is no > >>>> different from the ToIntFunction approach. > >>>> > >>>> > >>>> On Thu, Jul 7, 2022 at 9:23 PM Maxim Muzafarov <mmu...@apache.org> > >>> wrote: > >>>> > >>>>> Folks, > >>>>> > >>>>> I'd like also to mention since we are talking about a customer's > >>>>> custom affinity function and affinity mapper implementations we could > >>>>> face with some issues during these classes instantiation. It could > >>>>> work for the customer which I've faced on, but I cannoun be sure that > >>>>> this approach will work for all of the cases. > >>>>> > >>>>> I think it is better to avoid such an issues and leave it up to a > >>>>> user. Nevertheless, the worst scenario for the user would be having 2 > >>>>> hops on each put/get as it was before this thread. > >>>>> > >>>>> On Thu, 7 Jul 2022 at 21:12, Maxim Muzafarov <mmu...@apache.org> > >>> wrote: > >>>>>> > >>>>>> Folks, > >>>>>> > >>>>>> I'm not familiar with a thin client protocol, so, please, correct me > >>>>>> if I'm wrong - is it possible sending classes over the network for > >>>>>> different type of thin clients? It seems to me it will not work. I > >>>>>> think it is possible to use class name/or type id and we are capable > >>>>>> to instantiate both of the AffinityFunction and AffinityKeyMapper > >>> (it > >>>>>> will be required too) classes. However, this approach requires of > >>>>>> these classes to be present on a thin client side and it can be > >>> tricky > >>>>>> to configure if this client is used inside a container (e.g. with > >>>>>> spring data or something). > >>>>>> > >>>>>> Setting directly some kind of a known mapper looks more > >>>>>> straightforward and error prone approach. > >>>>>> > >>>>>> Please, correct me if I am wrong. > >>>>>> > >>>>>> On Thu, 7 Jul 2022 at 21:02, Семён Данилов <samvi...@yandex.ru> > >>> wrote: > >>>>>>> > >>>>>>> +1 to Pavel’s approach. Giving user the ability to set affinity > >>>>> function that is potentially different from the one that is on server > >>>>> doesn’t look good. > >>>>>>> > >>>>>>> I’d even go further and try sending the affinity function class > >>> itself > >>>>> over the network, so users won’t have to alter the classpath by > >>> adding the > >>>>> class that is not directly used in the codebase. > >>>>>>> On 7 Jul 2022, 21:41 +0400, Pavel Tupitsyn <ptupit...@apache.org > >>>> , > >>>>> wrote: > >>>>>>>> Can we actually avoid any public API changes and do the > >>> following: > >>>>>>>> > >>>>>>>> When a feature flag is present and there is a custom affinity > >>>>> function on > >>>>>>>> the server, send back the class name (or binary type id, if > >>>>> possible) of > >>>>>>>> the affinity function? > >>>>>>>> Then simply instantiate it on the client and call > >>> `partition(Object > >>>>> key)` > >>>>>>>> on it? > >>>>>>>> > >>>>>>>> On Thu, Jul 7, 2022 at 8:32 PM Maxim Muzafarov < > >>> mmu...@apache.org> > >>>>> wrote: > >>>>>>>> > >>>>>>>>> Pavel, > >>>>>>>>> > >>>>>>>>> Here is my thoughts. > >>>>>>>>> > >>>>>>>>> As I mentioned before, we will need only the > >>>>>>>>> AffinityFunction#partition(Object key) method for calculation > >>> on > >>>>> the > >>>>>>>>> client side due to all the partition-to-node mappings will be > >>>>>>>>> requested asynchronously from a server node how it is > >>> happening now > >>>>>>>>> for cache groups with the default affinity function. Thus > >>> setting > >>>>> the > >>>>>>>>> AffinityFunction looks on the client side redundant and it > >>> can be > >>>>>>>>> transformed to a simple ToInFunction<Object> interface. > >>>>>>>>> > >>>>>>>>> public interface ToIntFunction<Object> { > >>>>>>>>> int applyAsInt(Object key); > >>>>>>>>> } > >>>>>>>>> > >>>>>>>>> Another point that I'd like also to mention is that the cache > >>>>> already > >>>>>>>>> created in a cluster, so it will be better to eliminate the > >>>>> duplicate > >>>>>>>>> affinity function configuration (setting the number of > >>>>> partitions). It > >>>>>>>>> is fully possible to receive the number of partitions from a > >>> server > >>>>>>>>> node (the same way as it currently happening). Thus instead > >>> of the > >>>>>>>>> ToInFunction<Object> interface it will be better to use > >>>>>>>>> ToInBiFunction<Object, Integer>. > >>>>>>>>> > >>>>>>>>> public interface ToIntBiFunction<Object, Integer> { > >>>>>>>>> int applyAsInt(Object key, Integer parts); > >>>>>>>>> } > >>>>>>>>> > >>>>>>>>> > >>>>>>>>> I agree with you that "setPartitionAwarenessKeyMapper" may be > >>> is > >>>>> not > >>>>>>>>> good naming here, we can rename it and move it to the public > >>> API, > >>>>> of > >>>>>>>>> course. > >>>>>>>>> > >>>>>>>>> On Thu, 7 Jul 2022 at 20:06, Pavel Tupitsyn < > >>> ptupit...@apache.org> > >>>>> wrote: > >>>>>>>>>> > >>>>>>>>>> Maxim, > >>>>>>>>>> > >>>>>>>>>> I am confused. We were talking about a custom Affinity > >>> Function. > >>>>>>>>>> As you noted, AffinityKeyMapper is deprecated, why do we add > >>>>> something > >>>>>>>>>> named "setPartitionAwarenessKeyMapper"? > >>>>>>>>>> > >>>>>>>>>> Internal API approach is hacky. > >>>>>>>>>> IMO we should either develop a proper feature with a good > >>> public > >>>>> API, or > >>>>>>>>>> not add anything at all. > >>>>>>>>>> > >>>>>>>>>> On Thu, Jul 7, 2022 at 6:34 PM Maxim Muzafarov < > >>>>> mmu...@apache.org> > >>>>>>>>> wrote: > >>>>>>>>>> > >>>>>>>>>>> Folks, > >>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>>>> Thank you for your comments. > >>>>>>>>>>> > >>>>>>>>>>> First of all, I'd like to point out that if the cache is > >>>>> created with > >>>>>>>>>>> a custom affinity function or the legacy AffinityKeyMapper > >>>>> interface, > >>>>>>>>>>> the thin client should be able to provide only a > >>>>> `key-to-partition` > >>>>>>>>>>> mapping function to handle the case described above. The > >>>>>>>>>>> `partition-to-node` mappings the client will receive from > >>> a > >>>>> server > >>>>>>>>>>> node it connected to. This will simplify a bit the final > >>>>> solution. > >>>>>>>>>>> > >>>>>>>>>>> ================== > >>>>>>>>>>> > >>>>>>>>>>> I've checked your suggestions and it looks like both of > >>> them > >>>>> have some > >>>>>>>>>>> sufficient drawbacks: > >>>>>>>>>>> > >>>>>>>>>>> 1. Using SystemProperty looks really hacky and we are > >>>>> explicitly > >>>>>>>>>>> complicate a thin client configuration for an end user. > >>>>>>>>>>> > >>>>>>>>>>> 2. Extending the ClientCacheConfiguration is a very good > >>> and > >>>>>>>>>>> straightforward idea, however it doesn't fit the case > >>>>> described above. > >>>>>>>>>>> Caches previously created with custom affinity > >>> functions/key > >>>>> mappers > >>>>>>>>>>> already present in the cluster, so in this case we are > >>> forcing > >>>>> a user > >>>>>>>>>>> to store an additional ClientCacheConfiguration. This is > >>> not > >>>>> good. The > >>>>>>>>>>> cache.getOrCreate(cfg) method will also be used and fire > >>> in > >>>>> turn > >>>>>>>>>>> CACHE_GET_OR_CREATE_WITH_CONFIGURATION request which is > >>> not > >>>>> necessary > >>>>>>>>>>> here. For this case using cache.name(str) is only enough. > >>>>>>>>>>> > >>>>>>>>>>> ================== > >>>>>>>>>>> > >>>>>>>>>>> I propose the following two solutions that looks very > >>>>> promising: > >>>>>>>>>>> > >>>>>>>>>>> 3. Extending cache create methdos with a > >>> ClientCacheContext in > >>>>> the > >>>>>>>>>>> IgniteClient interface. This context will contain all > >>>>> additional cache > >>>>>>>>>>> attributes like custom cache affinity mappers that map > >>> cache > >>>>> keys to > >>>>>>>>>>> partitions if a custom affinity was used on the server > >>> side > >>>>> (note that > >>>>>>>>>>> all partition-to-node mappings will be received by thin > >>> client > >>>>> from a > >>>>>>>>>>> server node). > >>>>>>>>>>> > >>>>>>>>>>> interface IgniteClientEx extends IgniteClient { > >>>>>>>>>>> ClientCache<K, V> name(String name, ClientCacheContext > >>> cctx); > >>>>>>>>>>> ClientCache<K, V> getOrCreateCache(String name, > >>>>> ClientCacheContext > >>>>>>>>>>> cctx); > >>>>>>>>>>> ClientCache<K, V> > >>> getOrCreateCache(ClientCacheConfiguration > >>>>> cfg, > >>>>>>>>>>> ClientCacheContext cctx); > >>>>>>>>>>> } > >>>>>>>>>>> > >>>>>>>>>>> class ClientCacheContext { > >>>>>>>>>>> setPartitionAwarenessKeyMapper(ToIntBiFunction<Object, > >>> Integer> > >>>>>>>>>>> mapper); > >>>>>>>>>>> } > >>>>>>>>>>> > >>>>>>>>>>> 4. Use the same approach as the IgniteCache interface > >>> does for > >>>>> the > >>>>>>>>>>> same things - adding withPartitionAwarenessKeyMapper() to > >>> the > >>>>>>>>>>> interface. This method will allow to configure the thin > >>> client > >>>>>>>>>>> execution behaviour for the partition awareness feature by > >>>>> setting a > >>>>>>>>>>> custom cache key mapper. > >>>>>>>>>>> > >>>>>>>>>>> ================== > >>>>>>>>>>> > >>>>>>>>>>> I've used the 4-th solution due to it brings much less > >>> source > >>>>> code to > >>>>>>>>>>> the Apache Ignite codebase and looks a bit simpler to > >>>>> configure for a > >>>>>>>>>>> user. I've also move the withPartitionAwarenessKeyMapper() > >>>>> method to > >>>>>>>>>>> an internal API interface which still solves a user issue > >>> with > >>>>> the > >>>>>>>>>>> partition awareness, but also specifies that the custom > >>> mapping > >>>>>>>>>>> function and deprecated AffinityKeyMapper should not be > >>> used, > >>>>> in > >>>>>>>>>>> general. > >>>>>>>>>>> > >>>>>>>>>>> Please, take a look at my patch: > >>>>>>>>>>> > >>>>>>>>>>> https://issues.apache.org/jira/browse/IGNITE-17316 > >>>>>>>>>>> https://github.com/apache/ignite/pull/10140/files > >>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>>>> On Fri, 1 Jul 2022 at 14:41, Pavel Tupitsyn < > >>>>> ptupit...@apache.org> > >>>>>>>>> wrote: > >>>>>>>>>>>> > >>>>>>>>>>>> I have no objections to extending the Thin Client > >>>>> configuration with > >>>>>>>>> a > >>>>>>>>>>>> pluggable Affinity Function. > >>>>>>>>>>>> Let's make it a normal Java setter though, system > >>> properties > >>>>> are > >>>>>>>>> hacky. > >>>>>>>>>>>> Especially when only some of the caches use custom > >>> affinity, > >>>>> as Maxim > >>>>>>>>>>>> mentioned. > >>>>>>>>>>>> > >>>>>>>>>>>> On Wed, Jun 29, 2022 at 7:20 PM Николай Ижиков < > >>>>> nizhi...@apache.org> > >>>>>>>>>>> wrote: > >>>>>>>>>>>> > >>>>>>>>>>>>> +1 to have ability to specify custom affinity for PA > >>> on > >>>>> thin > >>>>>>>>> client. > >>>>>>>>>>>>> > >>>>>>>>>>>>> It seems to me custom affinity is a rare use-case of > >>>>> Ignite API. > >>>>>>>>>>>>> Propose to have SystemProperty that can specify > >>> affinity > >>>>>>>>> implementation > >>>>>>>>>>>>> for a thin client. > >>>>>>>>>>>>> > >>>>>>>>>>>>> > >>>>>>>>>>>>>> 29 июня 2022 г., в 18:53, Maxim Muzafarov < > >>>>> mmu...@apache.org> > >>>>>>>>>>>>> написал(а): > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> Igniters, > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> I've faced with a customer's cluster which has more > >>> than > >>>>> 150 > >>>>>>>>> nodes > >>>>>>>>>>> and > >>>>>>>>>>>>>> most for them are the thick-client nodes. Due to > >>> each > >>>>>>>>> thick-client is > >>>>>>>>>>>>>> a full-fledged cluster topology participant it > >>> affects > >>>>> the > >>>>>>>>> cluster > >>>>>>>>>>>>>> discovery machinery during the system operation and > >>>>> adding an > >>>>>>>>>>>>>> additional overhead for using/deploying a new nodes > >>> in > >>>>> Kubernetes > >>>>>>>>>>>>>> environment. However, the main thing from my point > >>> of > >>>>> view it > >>>>>>>>>>> prevents > >>>>>>>>>>>>>> updating the client side and server side components > >>>>> independently > >>>>>>>>>>>>>> (Apache Ignite doesn't support rolling upgrade). > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> Accordingly to the assumptions above using thin > >>> clients > >>>>> become a > >>>>>>>>>>>>>> necessary. This looks even more attractive, since > >>> the > >>>>> thin > >>>>>>>>> client has > >>>>>>>>>>>>>> a fairly rich API over the past few releases. > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> The MAIN ISSUE here that blocks thin client usage is > >>>>> that for > >>>>>>>>> some of > >>>>>>>>>>>>>> cache groups a custom affinity function (and an > >>>>>>>>> AffinityKeyMapper) > >>>>>>>>>>> was > >>>>>>>>>>>>>> used which prevents enabling the Partition Awareness > >>>>> thin client > >>>>>>>>>>>>>> feature. Thus each cache request will have two hops. > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> Of course, we can force users to migrate to a new > >>> API, > >>>>> but this > >>>>>>>>>>>>>> becomes more difficult when Apache Ignite is part > >>> of a > >>>>> much > >>>>>>>>> larger > >>>>>>>>>>>>>> architectural solution and thus it is doent' looks > >>> so > >>>>> friendly. > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> The MAIN QUESTION here - does anyone know our users > >>> who > >>>>> have > >>>>>>>>>>>>>> encountered with the same issue? I want to solve > >>> such a > >>>>> problem > >>>>>>>>> once > >>>>>>>>>>>>>> and make all such users happy by implementing the > >>> general > >>>>>>>>> approach. > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> = Possible solutions = > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> 1. Making an affinity function pluggable (mapping > >>>>> calculations) > >>>>>>>>> on > >>>>>>>>>>> the > >>>>>>>>>>>>>> thin clients side. Currently the > >>>>> RendezvousAffinityFunction [1] > >>>>>>>>> is > >>>>>>>>>>>>>> only supported > >>>>>>>>>>>>>> for the partition awareness. A user's affinity > >>> function > >>>>> seems to > >>>>>>>>> be > >>>>>>>>>>>>>> the stateless function due to there is no machinery > >>> to > >>>>> transfer > >>>>>>>>>>> states > >>>>>>>>>>>>>> to the thin client. > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> Pros - a general solution for all such cases; > >>>>>>>>>>>>>> Cons - unnecessary complexity, extending public API; > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> 2. Creating an Ignite extension which will extend > >>> the > >>>>> thin > >>>>>>>>> client API > >>>>>>>>>>>>>> thus a user will have a full control over a > >>> destination > >>>>> node to > >>>>>>>>> which > >>>>>>>>>>>>>> requests being sent. > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> Pros - isolated solution, simple implementation; > >>>>>>>>>>>>>> Cons - hard to support spring-boot-thin-client etc. > >>> and > >>>>> other > >>>>>>>>>>>>>> extensions based on the thin client API; > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> Folks, please share your thoughts. > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> [1] > >>>>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>> > >>>>> > >>> > https://github.com/apache/ignite/blob/master/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCachePartitionsRequest.java#L206 > >>>>>>>>>>>>> > >>>>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>> > >>>>> > >>> > >> > >