Replies: 3 comments 3 replies
-
I am a bit confused why you can't just use one |
Beta Was this translation helpful? Give feedback.
-
@yangty89 let me think a bit more about this... |
Beta Was this translation helpful? Give feedback.
-
Hi @normanmaurer, I think that an Returning to our topic in question, the chooser relies on the information of a channel (whether it's shared or dedicated) to make an appropriate decision. It's to some extent akin to the "sticky sessions" mode of a load balancer, in that they both make use of specific information provided by connections. From this point of view I think it might be appropriate to expose channels' information to the chooser. Aside from the approach mentioned above, I think that adding to the interface EventExecutorChooser {
/**
* Returns the new {@link EventExecutor} to use.
*/
EventExecutor next();
/**
* @param obj an object to be used with the returned EventExecutor (e.g. a channel being registered to an EventLoop)
* @return a selected EventExecutor to use
*/
default EventExecutor next(Object obj) {return next();} // call the next() method by default to avoid breaking the current API usage
} // add the method below in class MultithreadEventExecutorGroup
public EventExecutor next(Object object) {
return chooser.next(object);
}
// add/modify the methods below in class MultithreadEventLoopGroup
public EventLoop next(Channel channel) {
return (EventLoop) super.next(channel);
}
public ChannelFuture register(Channel channel) {
return next(channel).register(channel);
} // a simple version of customized chooser for identifying the type of the connection and act accordingly
private static final class CustomizedExecutorChooser implements EventExecutorChooserFactory.EventExecutorChooser {
private final AtomicInteger sharedConnIdx = new AtomicInteger(); // shared connection index
private final AtomicInteger connIdx = new AtomicInteger(); // common connection index (e.g. for dedicated connection)
private final EventExecutor[] executors;
CustomizedExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[connIdx.getAndIncrement() & executors.length - 1]; // use a common index here
}
@Override
public EventExecutor next(Object object) {
Channel channel = (Channel) object;
// if it's a shared connection, use the shared connection index for selection, otherwise use a common index
if (Objects.equals("shared", channel.attr(AttributeKey.valueOf("connectionType")).get())) {
return executors[sharedConnIdx.getAndIncrement() & executors.length - 1];
}
return executors[connIdx.getAndIncrement() & executors.length - 1];
}
} |
Beta Was this translation helpful? Give feedback.
-
Hi, I'm working on a potential improvement for spring-data-redis. While communicating with Redis using Lettuce via
LettuceConnectionFactory
, the component will by default maintain and inject into eachLettuceConnection
instance a shared connection that could serve multiple business threads simultaneously. This functionality is implemented based on netty and it enables Lettuce to communicate efficiently with Redis in a pipelining way.As the
LettuceConnectionFactory
currently creates and utilize only one shared connection, I'm thinking about increasing its quantity, so that we could exploit the parallelism of the underlying machine and gain a better performance. The key point here is that we should distribute evenly the shared connections across different IOEventLoop
s, so as to achieve a "good" parallelism.It would be fine if we only use the shared connection to interact with Redis, however, in the case of sending transactional, pipelining or blocking commands to Redis, a
LettuceConnection
would create a new connection called "dedicated connection", which is dedicated (but also tends to be short lived) to the current business thread, in order to process the request in question without risking interfering with other business threads.The problem lies in that both the shared connections and the dedicated connections would be bound to the same IO
EventLoopGroup
and thus share the sameEventExecutorChooser
instance. In the worst-case scenario, all the shared connections might turn out to be bound to only a half ofEventLoop
s because of the interference of dedicated connections.I wonder consequently if it's feasible to implement a finer granularity of
EventExecutorChooser
management and utilization. For the problem mentioned above, we might simply address it by introducing another chooser for the shared connections, which functions independently with the original one.I think maybe we could add a
ChannelOption
forEventExecutorChooser
, which could be configured by the client, and act accordingly during channel registration. It might look like something below (some code omitted). I would like to know your opinion on this, thanks :)Beta Was this translation helpful? Give feedback.
All reactions