[jboss-jira] [JBoss JIRA] (WFLY-11489) SFSB not sticky on a single cluster node when clustering of the bean is disabled

Richard Achmatowicz (Jira) issues at jboss.org
Fri Jan 11 13:20:00 EST 2019


    [ https://issues.jboss.org/browse/WFLY-11489?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13681107#comment-13681107 ] 

Richard Achmatowicz edited comment on WFLY-11489 at 1/11/19 1:19 PM:
---------------------------------------------------------------------

I've now had a look in detail at the affinity processing here and have an idea for a fix. There are three problems to overcome. 

The first is to correct the assignment of strong and weak affinity for the SFSB with passivationEnabled == false. If the initial affinity of the proxy before session creation is (strong affinity, weak affinity) = (NONE, NONE), which is the default, then the affinity assignment we expect is either (NODE, NONE) or (NONE, NODE) which are equivalent. In other words, invocations should be tied to the node that the session is created on.

The second problem is that the v3 protocol will not allow sending arbitrary values affinity back to the client: it is assumed that:
* updates to strong affinity are always of type ClusterAffinity 
* updates to weak affinity are always of type NodeAffinity

For the code, see for example  https://github.com/wildfly/jboss-ejb-client/blob/master/src/main/java/org/jboss/ejb/protocol/remote/EJBServerChannel.java#L705
This means that we can't assign (NODE, NONE) to the SFSB with passivationEnabled=false, but we can assign (NONE, NODE) which is equivalent. This seems to be the only way around this particular issue.

The third problem is that, on the client side, when the reply from the server is unpacked, there are some adjustments made to the affinity values before the invocation completes. These adjustments seem to interpret Affinity.NONE as "the affinity is not set", and try to replace Affinity.NONE with the targetAffinity which was determined when doing discovery. For example: https://github.com/wildfly/jboss-ejb-client/blob/master/src/main/java/org/jboss/ejb/client/DiscoveryEJBClientInterceptor.java#L172. In fact, Affinity.NONE means "I don't care which node you send me to" and does not mean  "the affinity is not set". So, for example, the affinity adjustment made in the DiscoveryEJBClientInterceptor above will transform (NONE, NODE) into (NODE, NODE) or possibly (URI, NODE) where URI is a URIAffinity assigment for the locator pointing to the server used to create the session. In this case, such a manipulation may not hurt, but it seems to be unnecessary. 

So, i'll be putting together a fix which incorporates these three changes. It would have been much easier and cleaner to be able to assign to the strong or weak affinity any type of affinity, but with v3, that is currently not possible.

PS For those interested, targetAffinity is assigned when we choose a target for the invocation. Doing discovery to choose a target results in a serviceURL which contains a location and node, module and cluster attributes associated with the serviceURL. The location tells us how to connect to the node, the attributes tell us what the node name is, which modules are deployed there and which clusters it belongs to. targetAffinity is NodeAffinity(<node name>) if the serviceURL does have a node attribute, and URIAffinity(<location>) if there is no node attribute.  


was (Author: rachmato):
I've now had a look in detail ate the affinity processing here and have an idea for a fix. There are three problems to overcome. 

The first is to correct the assignment of strong and weak affinity for the SFSB with passivationEnabled == false. If the initial affinity of the proxy before session creation is (strong affinity, weak affinity) = (NONE, NONE), which is the default, then the affinity assignment we expect is either (NODE, NONE) or (NONE, NODE) which are equivalent. In other words, invocations should be tied to the node that the session is created on.

The second problem is that the v3 protocol will not allow sending arbitrary values affinity back to the client: it is assumed that:
* updates to strong affinity are always of type ClusterAffinity 
* updates to weak affinity are always of type NodeAffinity
For the code, see for example  https://github.com/wildfly/jboss-ejb-client/blob/master/src/main/java/org/jboss/ejb/protocol/remote/EJBServerChannel.java#L705
This means that we can't assign (NODE, NONE) to the SFSB with passivationEnabled=false, but we can assign (NONE, NODE) which is equivalent. This seems to be the only way around this particular issue.

The third problem is that, on the client side, when the reply from the server is unpacked, there are some adjustments made to the affinity values before the invocation completes. These adjustments seem to interpret Affinity.NONE as "the affinity is not set", and try to replace Affinity.NONE with the targetAffinity which was determined when doing discovery. For example: https://github.com/wildfly/jboss-ejb-client/blob/master/src/main/java/org/jboss/ejb/client/DiscoveryEJBClientInterceptor.java#L172. In fact, Affinity.NONE means "I don't care which node you send me to" and does not mean  "the affinity is not set". So, for example, the affinity adjustment made in the DiscoveryEJBClientInterceptor above will transform (NONE, NODE) into (NODE, NODE) or possibly (URI, NODE) where URI is a URIAffinity assigment for the locator pointing to the server used to create the session. In this case, such a manipulation may not hurt, but it seems to be unnecessary. 

So, i'll be putting together a fix which incorporates these three changes. It would have been much easier and cleaner to be able to assign to the strong or weak affinity any type of affinity, but with v3, that is currently not possible.


> SFSB not sticky on a single cluster node when clustering of the bean is disabled
> --------------------------------------------------------------------------------
>
>                 Key: WFLY-11489
>                 URL: https://issues.jboss.org/browse/WFLY-11489
>             Project: WildFly
>          Issue Type: Bug
>          Components: Clustering, Remoting
>    Affects Versions: 15.0.0.Final
>         Environment: A clustered environment with 2 nodes. Both nodes started with an unmodified {{standalone-ha.xml}} configuration (see _Steps to Reproduce_)
> This issue happens on 15.0.0.Final and was tested as well as on current head (sha: 372697282dccefd0b9df48e6aa4dcb69e1c4b40f).
>            Reporter: Jörg Bäsner
>            Assignee: Richard Achmatowicz
>            Priority: Major
>         Attachments: reproducer.zip
>
>
> In case a stateful session bean is annotated with:
> {{@Stateful(passivationCapable=false)}}
> then the serialization is *disabled* and thus the bean is only available on a single cluster node.
> When a client now calls two different methods on this stateful bean it intermittently ends up on different cluster nodes, resulting in the following Exception:
> {code}
> ERROR [org.jboss.as.ejb3.invocation] (default task-2) WFLYEJB0034: EJB Invocation failed on component TestSessionEJB for method public abstract void test.ITestSession.method2(java.lang.String,java.lang.String) throws javax.ejb.EJBException,java.rmi.RemoteException: javax.ejb.NoSuchEJBException: WFLYEJB0168: Could not find EJB with id UUIDSessionID [4b0f4a27-40ba-411b-8852-0108a5ec64f4]
> 	at org.jboss.as.ejb3.component.stateful.StatefulComponentInstanceInterceptor.processInvocation(StatefulComponentInstanceInterceptor.java:55)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:54)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:509)
> 	at org.jboss.weld.module.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:81)
> 	at org.jboss.as.weld.ejb.EjbRequestScopeActivationInterceptor.processInvocation(EjbRequestScopeActivationInterceptor.java:89)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:47)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:100)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.as.ejb3.deployment.processors.StartupAwaitInterceptor.processInvocation(StartupAwaitInterceptor.java:22)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.as.ejb3.deployment.processors.EjbSuspendInterceptor.processInvocation(EjbSuspendInterceptor.java:57)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:67)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:60)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:438)
> 	at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:618)
> 	at org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:57)
> 	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
> 	at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:53)
> 	at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:198)
> 	at org.wildfly.security.auth.server.SecurityIdentity.runAsFunctionEx(SecurityIdentity.java:406)
> 	at org.jboss.as.ejb3.remote.AssociationImpl.invokeWithIdentity(AssociationImpl.java:565)
> 	at org.jboss.as.ejb3.remote.AssociationImpl.invokeMethod(AssociationImpl.java:546)
> 	at org.jboss.as.ejb3.remote.AssociationImpl.lambda$receiveInvocationRequest$0(AssociationImpl.java:197)
> 	at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
> 	at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
> 	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
> 	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1349)
> 	at java.lang.Thread.run(Thread.java:748)
> {code}



--
This message was sent by Atlassian Jira
(v7.12.1#712002)



More information about the jboss-jira mailing list