Details

    • Type: Improvement
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 1.0
    • Fix Version/s: 0.10.0
    • Component/s: None
    • Labels:
      None

      Description

      This is the parent Topic for the 1.0 release to introduce Multiplex Services with Apache Thrift.

      We need sub tasks here to manage language support, test suite, documentation & co.

      e.g. integrate Multiplex Services into cross language test suite THRIFT-847 via test/test.sh

        Issue Links

        1.
        Support for Multiplexing Services on any Transport, Protocol and Server Sub-task Closed Unassigned
         
        2.
        Python: Support for Multiplexing Services on any Transport, Protocol and Server Sub-task Closed Roger Meier
         
        3.
        Multiplexing support for the Ruby Library Sub-task Closed Jens Geyer
         
        4.
        Java: Allow multiplexing multiple services over a single TCP connection Sub-task Closed Roger Meier
         
        5.
        C++: Support for Multiplexing Services on any Transport, Protocol and Server Sub-task Closed Unassigned
         
        6.
        Delphi: Support for Multiplexing Services on any Transport, Protocol and Server Sub-task Closed Jens Geyer
         
        7.
        C#: Support for Multiplexing Services on any Transport, Protocol and Server Sub-task Closed Jens Geyer
         
        8.
        How can i use multi service in one program? Sub-task Closed Jake Farrell
         
        9.
        NodeJS: Support for Multiplexing Services Sub-task Closed Henrique Mendonça
         
        10.
        Erlang: Support for Multiplexing Services on any Transport, Protocol and Server Sub-task Closed David Robakowski
         
        11.
        Go: Support for Multiplexing Services on any Transport, Protocol and Server Sub-task Closed Unassigned
         
        12.
        Cocoa: Client-side support for Multiplexing Services on any Transport and Protocol Sub-task Closed Jens Geyer
         
        13.
        JavaScript: Support for Multiplexing Services Sub-task Closed Henrique Mendonça
         
        14.
        PHP: Client-side support for Multiplexing Services Sub-task Closed Jens Geyer
         
        15.
        PHP: Server-side support for Multiplexing Services Sub-task Closed Jens Geyer
         
        16.
        Haxe: Support for Multiplexing Services on any Transport, Protocol and Server Sub-task Closed Jens Geyer
         
        17.
        Perl: Support for Multiplexing Services on any Transport, Protocol and Server Sub-task Closed Unassigned
         
        18.
        Perl: Support for Multiplexing Services on any Transport, Protocol and Server Sub-task Closed Jens Geyer
         

          Activity

          Hide
          roger.meier Roger Meier added a comment -

          cross language test suite is key for success!
          ;-r

          Show
          roger.meier Roger Meier added a comment - cross language test suite is key for success! ;-r
          Hide
          billowqiu billow added a comment -

          good

          Show
          billowqiu billow added a comment - good
          Hide
          jking3 James E. King, III added a comment -

          This was solved in Jira THRIFT-66 for the C# library a long time ago... along with two-way communication, multiple outstanding requests, and SSL security with certificate management. That solution was practically a complete re-write of the C# library however. It looks like the generic solution does not rely on using the empty byte in the version 1 header that I used to allow for multiplexing of 256 services on the line, with backwards compatibility on service number 0. Regardless, I'm glad to see this is finally getting addressed.

          Show
          jking3 James E. King, III added a comment - This was solved in Jira THRIFT-66 for the C# library a long time ago... along with two-way communication, multiple outstanding requests, and SSL security with certificate management. That solution was practically a complete re-write of the C# library however. It looks like the generic solution does not rely on using the empty byte in the version 1 header that I used to allow for multiplexing of 256 services on the line, with backwards compatibility on service number 0. Regardless, I'm glad to see this is finally getting addressed.
          Hide
          jking3 James E. King, III added a comment -

          On thinking about this some more, it looks like the approach taken is not backwards compatible. In other words, you cannot produce a server that will listed on a single port an be able to handle older clients plus newer clients that are channel-aware. I'm not sure how far along this is overall as a project, but is backwards compatibility a concern or requirement? If it is, this would require a newer server to listen on an older port number for the older service, to handle older clients, and then to open another port to service multiplexed newer clients. There's no easy cut-over using the same port with the chosen technique. This introduces firewall complexities for upgrades because additional ports are now required. If the unused byte in the protocol header is used, then "channel zero" can handle the original, older monolithic service for the older clients, and newer clients can ignore "channel zero" and use channels 1..255 instead, all on the same port. This allows you to upgrade a server to one that has channel support and continue to service all your older clients without any additional security concerns.

          Show
          jking3 James E. King, III added a comment - On thinking about this some more, it looks like the approach taken is not backwards compatible. In other words, you cannot produce a server that will listed on a single port an be able to handle older clients plus newer clients that are channel-aware. I'm not sure how far along this is overall as a project, but is backwards compatibility a concern or requirement? If it is, this would require a newer server to listen on an older port number for the older service, to handle older clients, and then to open another port to service multiplexed newer clients. There's no easy cut-over using the same port with the chosen technique. This introduces firewall complexities for upgrades because additional ports are now required. If the unused byte in the protocol header is used, then "channel zero" can handle the original, older monolithic service for the older clients, and newer clients can ignore "channel zero" and use channels 1..255 instead, all on the same port. This allows you to upgrade a server to one that has channel support and continue to service all your older clients without any additional security concerns.
          Hide
          jensg Jens Geyer added a comment -

          Interesting discussion over there in THRIFT-66, I didn't know this before.

          However, I like the actual solution somewhat more, mainly for two reasons: (1) it does not rely on some additional magic well-known channel numbers that Server and Client have to know (2) it does not limit the number of multiplexed services to somewhat above 250. Ok, one might say that an IP adress or a port number is nothing else than (1) and that (2) is somewhat hypothetical.

          What's good about the channel solution: it does not add anything to the Messages, thus does not automatically affect traffic.

          Regarding compatibility: The new multiplexing uses a delimiter char. The existing code could be modified in such a way, where there is a default service (which would be the old, unmultiplexed service) which gets called whenever no delimiter is found in the name. If the default is null or empty, the code behaves as in the actual solution.

          Show
          jensg Jens Geyer added a comment - Interesting discussion over there in THRIFT-66 , I didn't know this before. However, I like the actual solution somewhat more, mainly for two reasons: (1) it does not rely on some additional magic well-known channel numbers that Server and Client have to know (2) it does not limit the number of multiplexed services to somewhat above 250. Ok, one might say that an IP adress or a port number is nothing else than (1) and that (2) is somewhat hypothetical. What's good about the channel solution: it does not add anything to the Messages, thus does not automatically affect traffic. Regarding compatibility: The new multiplexing uses a delimiter char. The existing code could be modified in such a way, where there is a default service (which would be the old, unmultiplexed service) which gets called whenever no delimiter is found in the name. If the default is null or empty, the code behaves as in the actual solution.
          Hide
          jking3 James E. King, III added a comment -

          If someone implements a multiplex listener in version 1.0 and updates their server, can the server still accept non-multiplexed traffic for backwards compatibility from older clients? If not, does that meet the requirements for thrift backwards compatibility (are there any)? I agree, the ~250 channels is not ideal, however it was a better solution than changing the protocol to version 2 and adding more space for it. The name is flexible, I like that. It will take up more space on the wire than a single byte and require more processing to decode (strchr + substr) than hitting a lookup table based on a slot number. All acceptable trace-offs in either direction if product requirements are met. Does this patch work to address two-way communications over the single established connection? The ability for the client to register as a service handler and for the server to do push notifications to the client over a service is a long-sought-for feature. This requires abstracting the endpoint so that either side can be a service handler. Was that discussed as a post-1.0 feature perhaps? Thanks.

          Show
          jking3 James E. King, III added a comment - If someone implements a multiplex listener in version 1.0 and updates their server, can the server still accept non-multiplexed traffic for backwards compatibility from older clients? If not, does that meet the requirements for thrift backwards compatibility (are there any)? I agree, the ~250 channels is not ideal, however it was a better solution than changing the protocol to version 2 and adding more space for it. The name is flexible, I like that. It will take up more space on the wire than a single byte and require more processing to decode (strchr + substr) than hitting a lookup table based on a slot number. All acceptable trace-offs in either direction if product requirements are met. Does this patch work to address two-way communications over the single established connection? The ability for the client to register as a service handler and for the server to do push notifications to the client over a service is a long-sought-for feature. This requires abstracting the endpoint so that either side can be a service handler. Was that discussed as a post-1.0 feature perhaps? Thanks.
          Hide
          codesf Randy Abernethy added a comment -

          I like the idea of a "default" service for providing backward compatibility on a port. I think the idea mentioned by Jens where a missing delimiter automatically selects the default service is a pretty clean solution.

          Show
          codesf Randy Abernethy added a comment - I like the idea of a "default" service for providing backward compatibility on a port. I think the idea mentioned by Jens where a missing delimiter automatically selects the default service is a pretty clean solution.
          Hide
          roger.meier Roger Meier added a comment -

          Does it make sense to have more than ~ 250 services on a communication port?
          Personally, I prefer the efficient and lightweight one byte approach it's more inline with the vision of Apache Thrift and there is no overhead for messages.

          roger
          ;-r

          Show
          roger.meier Roger Meier added a comment - Does it make sense to have more than ~ 250 services on a communication port? Personally, I prefer the efficient and lightweight one byte approach it's more inline with the vision of Apache Thrift and there is no overhead for messages. roger ;-r
          Hide
          jensg Jens Geyer added a comment - - edited

          I basically agree, but the experience is that people tend to use stuff for crazy things and in sometimes very unintended ways just because they can do it, so the 250 may become an issue at some point. On the other hand, both approaches are not interfering, so the string-prefix could even be mixed with the smaller and more efficient "channel byte" approach.

          The bottom line for me is, that I'm open to any one of the solutions, or even both. An definitive agreement about how we will proceed would be fine.

          PS: Does it make sense to separate the two-way issue from this one?

          Show
          jensg Jens Geyer added a comment - - edited I basically agree, but the experience is that people tend to use stuff for crazy things and in sometimes very unintended ways just because they can do it, so the 250 may become an issue at some point. On the other hand, both approaches are not interfering, so the string-prefix could even be mixed with the smaller and more efficient "channel byte" approach. The bottom line for me is, that I'm open to any one of the solutions, or even both. An definitive agreement about how we will proceed would be fine. PS: Does it make sense to separate the two-way issue from this one?
          Hide
          codesf Randy Abernethy added a comment -

          I think bidirectional communications support is an important feature that should be addressed as a standalone Jira.

          In regard to Roger’s comment, perhaps 563 could be given a transparent fast mode. Anytime the service string is 4 bytes or less it could be used as an i32 key. Thus if you want fast operations all you need do is keep your service IDs 4 chars or less. When the TMultiplexedProtocol sees a service ID <= 4 chars it uses a message that begins with the separator followed by the 4 byte key and then the normal “name” payload.

          The TMultiplexedProcessor in this scenario would check byte 0 for the separator, if found it would take the fast code path, no parsing just extract the key and call through to the correct service. Should be as fast as the byte solution. Longer service names would be processed as they are now. Calls without a separator could invoke a default service. This would give us fast, flexible and backward compatible in one package.However it works, I think a fast key lookup would be nice.

          Repurposing one of the Protocol version bytes seems problematic. It entangles the multiplexing concern with the otherwise encapsulated operations of the Protocol. It is really a message routing issue and plugging it into the message name seems pretty logical. Onthe pragmatic side, there may be protocols out there that implement TProtocol but have no spare bytes to use. For example, the JSON Protocol Version is a text based number, could work, but starts getting strange. The compact protocol has a one byte ID and a one byte Version packed with the message type, leaving no obvious way to hook in the channel byte.

          Show
          codesf Randy Abernethy added a comment - I think bidirectional communications support is an important feature that should be addressed as a standalone Jira. In regard to Roger’s comment, perhaps 563 could be given a transparent fast mode. Anytime the service string is 4 bytes or less it could be used as an i32 key. Thus if you want fast operations all you need do is keep your service IDs 4 chars or less. When the TMultiplexedProtocol sees a service ID <= 4 chars it uses a message that begins with the separator followed by the 4 byte key and then the normal “name” payload. The TMultiplexedProcessor in this scenario would check byte 0 for the separator, if found it would take the fast code path, no parsing just extract the key and call through to the correct service. Should be as fast as the byte solution. Longer service names would be processed as they are now. Calls without a separator could invoke a default service. This would give us fast, flexible and backward compatible in one package.However it works, I think a fast key lookup would be nice. Repurposing one of the Protocol version bytes seems problematic. It entangles the multiplexing concern with the otherwise encapsulated operations of the Protocol. It is really a message routing issue and plugging it into the message name seems pretty logical. Onthe pragmatic side, there may be protocols out there that implement TProtocol but have no spare bytes to use. For example, the JSON Protocol Version is a text based number, could work, but starts getting strange. The compact protocol has a one byte ID and a one byte Version packed with the message type, leaving no obvious way to hook in the channel byte.
          Hide
          jking3 James E. King, III added a comment -

          Good point, the solution in THRIFT-66 is compatible with the binary protocol because it had that spare byte in it and that's what I planned to use in my project at the time, but I didn't implement a solution for any other protocol, however conceptually they would be more obvious in text based protocols like JSON or HTTP, it would require changes to each protocol to support the channel concept. Another worry I had which was not a problem where the project was being used (since it was all C#) was whether all clients initialized that part of the VERSION_1 header to zero or not. It appeared that they did.

          Show
          jking3 James E. King, III added a comment - Good point, the solution in THRIFT-66 is compatible with the binary protocol because it had that spare byte in it and that's what I planned to use in my project at the time, but I didn't implement a solution for any other protocol, however conceptually they would be more obvious in text based protocols like JSON or HTTP, it would require changes to each protocol to support the channel concept. Another worry I had which was not a problem where the project was being used (since it was all C#) was whether all clients initialized that part of the VERSION_1 header to zero or not. It appeared that they did.
          Hide
          drennalls David Rennalls added a comment -

          Is there a sub-task for Perl multiplexing support as well that's not linked to this parent topic ?

          Show
          drennalls David Rennalls added a comment - Is there a sub-task for Perl multiplexing support as well that's not linked to this parent topic ?
          Hide
          jensg Jens Geyer added a comment -

          Hi David Rennalls,

          seems that you are right and there is indeed no ticket for Perl, yet.
          You are free to create one and link it to this one.

          Did I mention that we also accept patches?

          Show
          jensg Jens Geyer added a comment - Hi David Rennalls , seems that you are right and there is indeed no ticket for Perl, yet. You are free to create one and link it to this one. Did I mention that we also accept patches?
          Hide
          jking3 James E. King, III added a comment -

          Let's say I have a server running TBinaryProtocol, and I want to plan an upgrade to simplify the maintainability of the server by breaking up a massive service into multiplexed services. Further, I must require clients to be upgraded first, so I need the client to be able to talk to the old TBinaryProtocol when connecting to an old server as well as a new TMultiplexedProtocol (which is essentially a break-out of the services by functional area provided on the older interface). Do I need to allocate a new port number on the new server for the multiplexed protocol implementation and then have the client "try to connect to both, new then if that fails old"? I'd prefer to have this all work on the same port number if possible but I don't see how.

          Flip it around and say I want to upgrade the server to allow connections from old or new clients. Would there be a way to have the TMultiplexedProtocol implementation on the server recognize that the client is sending a TBinaryProtocol and forward the request to a default or fallback service? Both the old and new services would share the same common implementation code, just two different ways to get to it.

          Show
          jking3 James E. King, III added a comment - Let's say I have a server running TBinaryProtocol, and I want to plan an upgrade to simplify the maintainability of the server by breaking up a massive service into multiplexed services. Further, I must require clients to be upgraded first, so I need the client to be able to talk to the old TBinaryProtocol when connecting to an old server as well as a new TMultiplexedProtocol (which is essentially a break-out of the services by functional area provided on the older interface). Do I need to allocate a new port number on the new server for the multiplexed protocol implementation and then have the client "try to connect to both, new then if that fails old"? I'd prefer to have this all work on the same port number if possible but I don't see how. Flip it around and say I want to upgrade the server to allow connections from old or new clients. Would there be a way to have the TMultiplexedProtocol implementation on the server recognize that the client is sending a TBinaryProtocol and forward the request to a default or fallback service? Both the old and new services would share the same common implementation code, just two different ways to get to it.
          Hide
          jensg Jens Geyer added a comment -

          We've dicussed the upgrade scenario above, and the recommended solution is still to patch the server side in a way, where there is a fallback to a given default (which should be the previously existing service) if there is no delimiter char within the service name. This is already partially implemented in some parts of the lib, unfortunately not in all of them.

          Show
          jensg Jens Geyer added a comment - We've dicussed the upgrade scenario above , and the recommended solution is still to patch the server side in a way, where there is a fallback to a given default (which should be the previously existing service) if there is no delimiter char within the service name. This is already partially implemented in some parts of the lib, unfortunately not in all of them.

            People

            • Assignee:
              Unassigned
              Reporter:
              roger.meier Roger Meier
            • Votes:
              0 Vote for this issue
              Watchers:
              11 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development