[
https://issues.apache.org/jira/browse/THRIFT-3084?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14490814#comment-14490814
]
James E. King, III commented on THRIFT-3084:
--------------------------------------------
Hi Randy,
I do understand what you are saying however I must respectfully disagree with
the argument. Please take a look at the files I posted in THRIFT-3083. I
think the elegance of boiling down a server to the implementation of "a client
connected", "a client disconnected", and the ability to add additional
post-conditions to serve() is exactly what C++ was intended for... I think what
you are arguing for is the ability to subclass the servers as well as make the
servers understandable to junior C++ engineers. I feel that it is extremely
important to have consistent serve() and client handling behavior which is why
I introduced 3081 and 3083 into Jira.
My biggest concern with not doing this work is that the different framework
servers will behave in different ways even though they intend to provide the
same post-conditons. Case in point, if you look at the pre-THRIFT-3083
TThreadPoolServer::serve() handling if TTransportException, is is quite
different from TSimpleServer and TThreadedSevrer, when in fact it wants to be
the same since there is only on TServerTransport, and there should be
consistent exception behavior for TServerTransport no matter what is consuming
it. One logs some issues and one does not. In another case, TSimpleServer
will attempt to close the client if an error occurs, but the TThreadedServer
only attempts to close the input and output protocol transports and makes to
attempt to close the client. Both subclasses need to enforce the same setof
post-conditions so why do they differ/ They differ because identical code was
copied and modified instad of being consolidated.
With the introduction of THRIFT-2441 I had to modify three implementations of
TServer to ensure they were properly handling TTransportException(INTERRUPTED).
I think it makes sense to have a single instantiation of the server serve()
and a single instantiation of the client run loop since the generated code
depends on reliable interface contracts, as does the TServerTransport.
Given the processing logic in a TSimpleServer and a TThread*Server wants to be
identical ffor a given client, this is why I introduced THRIFT-3081. On
further observation is was clear that the three sevrers save the non-blocking
server had extremely similar logic patterns, so it made sense to me to
consolidate and {{standardize}} their behavior so that folks using the
framework could experience consistent behavior when switch between server types
provided by the framework. I belive the combination of 2441, 3081, 3083, and
3084 will yield a minimum viable production quality server provided by the
framework proper, where folks who want to use Thrift will no longer need to
roll their own TSevrer to achieve enterprise quality behavior. This should
encourage adoption and reduce intergation effort. Given other projects like
protobuf only provide the protocol portion, enhancing the transport and server
should further distance the project as useful from alternatives.
One thing I absolutely love about the original concept of thrift was the clear
separation of processor, protocol and transport. I find this to be unique
within the field and the changes I have made [hopefully] do not violate those
core axioms. TO answer your question - yes, TSimpleServer and any other
TServer including TThreadPoolServer should handle clients in a consistent
manner. The differences between the servers has been boiled down to the
following three items:
1. How do I handle a new client connection?
2. How do I handle a client that has disconnected?
3. How to I ensure that a post-condition of serve() is that no clients are
connected?
The changes in THRIFT-3083 make this very clear and easy to do.
In argument to your statement that TSimpleServer be self-contained and distinct
from other servers, , if TSimpleServer and TThreadedServer have 90% common code
and 10% divergent code in the respect of items 1 and 3 above, why should the
common code be replicated such tht is has a chance to diverge in behavior? It
should notbe different, because it is in fact the same, and I would encourage
any C++ engineer to avoid code duplication with the same set of changes that I
have submitted to the project, because in the end when code is not duplicated,
it only needs to be tested once to ensure it is functioning properly.
TServerTransport makes it easy (apart from the crazy constructor variances) for
anyone to make a server that differs in the areas where it matters most - the
three items I listed as 1,2,3 previously.
Thrift-3084 is specifically to ensure we do not accept() more clients than the
server allows; THRIFT-3083 is the right place to discuss TServer subclass code
duplication and the merits of such. I would argue the changes I have made
simplify maintenance because now there is only one place in the code one needs
to change the common client processing loop (THRIFT-3081) or the common server
processing loop (THRIFT-3083).\
> C++ add concurrent client limit to threaded servers
> ---------------------------------------------------
>
> Key: THRIFT-3084
> URL: https://issues.apache.org/jira/browse/THRIFT-3084
> Project: Thrift
> Issue Type: Improvement
> Components: C++ - Library
> Affects Versions: 0.8, 0.9, 0.9.1, 0.9.2
> Reporter: James E. King, III
>
> The TThreadedServer and TThreadPoolServer do not impose limits on the number
> of simultaneous connections, which is not useful in production as bad clients
> can drive a server to consume too many file descriptors or have too many
> threads.
> 1. Add a barrier to TServerTransport that will be checked before accept().
> 2. In the onClientConnected override (see THRIFT-3083) if the server reaches
> the limit of the number of accepted clients, enable the barrier.
> 3. In the onClientDisconnected override if the count of connected clients
> falls below the maximum concurrent limit, clear the barrier. This will allow
> the limit to be changed dynamically at runtime (lowered) with drain off
> clients until more can be accepted.
> Alternate proposal: Implement a Semaphore and have the servers block the
> serve() thread if the client that arrived puts the server at the concurrent
> client limit.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)