You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@guacamole.apache.org by "Kurt.Ding" <we...@fastonetech.com> on 2022/01/26 03:39:10 UTC

It is a efficient implementation about tunnel in guacamole common project that uses nio

>> Hi Guacamole Team
>>
>>     Our company use guacamole project in remote access service. But 
>> we found  that every connection always create an new thread for 
>> listening instructions from guacamole server(lets name it GS ) in
>>
>> org.apache.guacamole.websocket.GuacamoleWebSocketTunnelEndpoint#onOpen.
>>
>> Our solution write an nio implemention in listening instructions then 
>> pass  to websocket client, usually in  an broswer. Core idea is we 
>> create an bridger.  Let's take a further reads .
>>
>> When websocket Server  got open connection message, then websocket 
>> server create an bridger which contains a channel and a websocket 
>> session.  A channel  use to communicating to GS and websocket session 
>> use to communicating with websocket client.
>>
>> 1. Websocket start to  open Connection
>>
>> public BridgeropenConnection(WsSession wsSession, GuacamoleConfiguration  configuration) {
>>     Bridger bridger = createOneBridger(configuration); bridger.session = wsSession; try {
>>        bridger.channel =bridgerBootstrap.connect(); 
>> //TunnelEndpointNetty.GUACAD_HAND_MAP.put(channel!!.id().toString(), 
>> this) 
>> //TunnelEndpointNetty.BROWSER_HAND_MAP.put(session!!.id().toString(), 
>> this) bridger.sayHello(); }catch (GuacamoleException e) {
>>        logger.warn("Create tunnel failure ", e); }catch (IOException e) {
>>        logger.warn("Create tunnel failure ", e); }
>>     // open,send tunnel uuid bridger.sendInstruction(
>>           new GuacamoleInstruction(
>>                 GuacamoleTunnel.INTERNAL_DATA_OPCODE, bridger.getUUID().toString()
>>           )
>>     ); return bridger; }
>>
>> 2.  Nio channel connect to guacamole server
>>
>> public Channelconnect()throws IOException {
>>     ChannelFuture f =bootstrap.connect(guacdProperties.getHostname(), guacdProperties.getPort()); f.awaitUninterruptibly(CONNECT_WAIT_TIMEOUT); if (f.isCancelled()) {
>>        // Connection attempt cancelled by user logger.debug("Connect cancelled by client"); }else if (!f.isSuccess()) {
>>        logger.error("Connect error {}", f.cause().getCause()); }else {
>>        logger.info("Connect host {} port {} success", guacdProperties.getHostname(), guacdProperties.getPort()); return f.channel(); }
>>     throw new IOException("Connection error"); }
>>
>> 3. Bridger negotiates args  with guacamole server ,when bridger got 
>> ready instruction ,Now the bridger has been created and initialized 
>> success.
>>
>> @Override protected void channelRead0(ChannelHandlerContext ctx, GuacamoleInstruction msg)throws Exception {
>>     if (logger.isTraceEnabled()) {
>>        logger.trace("Get msg from guacad {}", msg); }
>>     Bridger tunnel = WebsocketHandlerAdapter.GUACAD_HAND_MAP.get(ctx.channel().id().toString()); //handle guacamole server connect instruction if (msg.getOpcode().equals("args")) {
>>        negotiateArgsThenConnect(ctx,msg,tunnel); }
>>     if (msg.getOpcode().equals("ready")) {
>>        receiveGuacamoleReady(ctx,msg,tunnel); }
>>     tunnel.receiveGuacamoleInstruction(msg); }
>>
>> 4. Bridger reveives guacamole instruction then forward it to 
>> websocket session
>>
>> public void receiveGuacamoleInstruction(GuacamoleInstruction ins) {
>>     try {
>>        session.sendText(ins.toString()); }catch (IOException e) {
>>        logger.error("Bridger send msg to error",e); try {
>>           close(); }catch (IOException ex) {
>>           logger.error("Bridger send msg to error",ex); }
>>     }
>> }
>>
>> 5. Bridger receives websocket message then forward it to guacamole server
>>
>> public void onMessage(String msg) {
>>     if(logger.isTraceEnabled()){
>>        logger.info("Send msg to guacd {}",msg); }
>>     GuacamoleInstruction instruction =null; try {
>>        instruction =browserDecoder.decode(msg); }catch (GuacamoleException e) {
>>        logger.error("Decoder ws msg error ",e); }
>>     //handle ws msg by code if (instruction.getOpcode().equals(GuacamoleTunnel.INTERNAL_DATA_OPCODE) || instruction.getOpcode().equals("nop")) {
>>
>>        // Respond to ping requests List<String> args = instruction.getArgs(); //ws ping if (args.size() >=2 && args.get(0).equals("ping")) {
>>           try {
>>              session.sendText(
>>                    new GuacamoleInstruction(
>>                          GuacamoleTunnel.INTERNAL_DATA_OPCODE, "ping", args.get(1)
>>                    ).toString()
>>              ); }catch (IOException e) {
>>              logger.error("Send msg to ws peer error",e); }
>>        }
>>        return; }
>>
>>     writeGuacamoleInstruction(instruction); }
>>
>> 6. Bridger receives close connection instruction from websocket , 
>> then close channel and websocket session in bridger
>>
>> public void close()throws IOException {
>>     channel.close(); session.close(); }
>>
>> I am looking forward to hearing from you .
>>
>> Thanks
>>
>> Kurt
>>

Re: It is a efficient implementation about tunnel in guacamole common project that uses nio

Posted by "Kurt.Ding" <we...@fastonetech.com>.
Hi Gucamole Team

Could you make some suggestions about  tools  which   is used to run  
vnc/rdp  benchmarks?

Thanks

Kurt


在 2022/2/16 16:07, Kurt.Ding 写道:
> Hi Mike Jumper
>
> I need some days to do benchmarks . After that I will provide you our 
> test report.
>
> I am looking forward to hearing from you.
>
> Thanks Kurt
>
> 在 2022/2/16 15:14, Mike Jumper 写道:
>> Can you provide any specific benchmarks/metrics showing that there is an
>> appreciable amount of CPU time being spent in thread context switches 
>> prior
>> to the proposed change, and a corresponding improvement after the 
>> change is
>> in place (for the same load)?
>>
>> - Mike
>>
>>
>> On Tue, Feb 15, 2022, 22:44 Kurt.Ding <we...@fastonetech.com> 
>> wrote:
>>
>>> Hi Nick
>>>
>>> I'm glad to hear from you. Let me answer your questions and then we
>>> could have a discuss.
>>>
>>> Firstly let's assume one user  create hundreds remote connection, then
>>> in the linux server  which is deployed websocket  container the java
>>> process creates  hundreds of thread , it cause high cpu usage .
>>>
>>> In our production  server(8 core 16g)  ,  we meet  the case dozens of
>>> users create about 100 remote connections, unfortunately every user
>>> can't use vnc/ssh smoothly . Then we fix this problem with upgrade our
>>> server spec
>>>
>>> Secondly, as we all knows , many threads running in one server results
>>> in  thread context switch , and wouldn't increase the number of request
>>> per second.
>>>
>>> I hope this will make sense for you. And Your suggestion about use
>>> existing classes is a good idea. I will follow your idea and have a 
>>> try.
>>>
>>> I am looking forward to have a discuss with you.
>>>
>>> Thanks Kurt
>>>
>>> 在 2022/2/15 22:23, Nick Couchman 写道:
>>>> On Tue, Feb 15, 2022 at 2:11 AM Kurt.Ding 
>>>> <we...@fastonetech.com>
>>>> wrote:
>>>>
>>>>> Hi Guacamole Team
>>>>>
>>>>> Was I wrong about this  thread running model? Look forward to your
>>> reply.
>>>>>
>>>> This is a bit outside my area of expertise, but I guess I'd start by
>>> asking
>>>> the following questions:
>>>> * What actual problem are you trying to solve? What problem is thread
>>>> creation causing for you? Why is it that you want to limit or 
>>>> reduce the
>>>> number of threads created? Is reducing the number of threads actually
>>> going
>>>> to resolve whatever problem you're concerned about, or is it just 
>>>> going
>>> to
>>>> move the problem to another place?
>>>> * Rather than creating a WebSocket bridge, would it make more sense to
>>>> integrate your changes into one of the existing classes, perhaps 
>>>> either
>>>> extending an existing GuacamoleTunnel implementation or just
>>> implementing a
>>>> new GuacamoleTunnel that could then be used within the code? That 
>>>> would
>>>> seem to avoid this extra step of having to tunnel your WebSocket
>>>> connections through another server/class.
>>>>
>>>> -Nick
>>>>

Re: It is a efficient implementation about tunnel in guacamole common project that uses nio

Posted by "Kurt.Ding" <we...@fastonetech.com>.
Hi Mike Jumper

I need some days to do benchmarks . After that I will provide you our 
test report.

I am looking forward to hearing from you.

Thanks Kurt

在 2022/2/16 15:14, Mike Jumper 写道:
> Can you provide any specific benchmarks/metrics showing that there is an
> appreciable amount of CPU time being spent in thread context switches prior
> to the proposed change, and a corresponding improvement after the change is
> in place (for the same load)?
>
> - Mike
>
>
> On Tue, Feb 15, 2022, 22:44 Kurt.Ding <we...@fastonetech.com> wrote:
>
>> Hi Nick
>>
>> I'm glad to hear from you. Let me answer your questions and then we
>> could have a discuss.
>>
>> Firstly let's assume one user  create hundreds remote connection, then
>> in the linux server  which is deployed websocket  container the java
>> process creates  hundreds of thread , it cause high cpu usage .
>>
>> In our production  server(8 core 16g)  ,  we meet  the case dozens of
>> users create about 100 remote connections, unfortunately every user
>> can't use vnc/ssh smoothly . Then we fix this problem with upgrade our
>> server spec
>>
>> Secondly, as we all knows , many threads running in one server results
>> in  thread context switch , and wouldn't increase the number of request
>> per second.
>>
>> I hope this will make sense for you. And Your suggestion about use
>> existing classes is a good idea. I will follow your idea and have a try.
>>
>> I am looking forward to have a discuss with you.
>>
>> Thanks Kurt
>>
>> 在 2022/2/15 22:23, Nick Couchman 写道:
>>> On Tue, Feb 15, 2022 at 2:11 AM Kurt.Ding <we...@fastonetech.com>
>>> wrote:
>>>
>>>> Hi Guacamole Team
>>>>
>>>> Was I wrong about this  thread running model? Look forward to your
>> reply.
>>>>
>>> This is a bit outside my area of expertise, but I guess I'd start by
>> asking
>>> the following questions:
>>> * What actual problem are you trying to solve? What problem is thread
>>> creation causing for you? Why is it that you want to limit or reduce the
>>> number of threads created? Is reducing the number of threads actually
>> going
>>> to resolve whatever problem you're concerned about, or is it just going
>> to
>>> move the problem to another place?
>>> * Rather than creating a WebSocket bridge, would it make more sense to
>>> integrate your changes into one of the existing classes, perhaps either
>>> extending an existing GuacamoleTunnel implementation or just
>> implementing a
>>> new GuacamoleTunnel that could then be used within the code? That would
>>> seem to avoid this extra step of having to tunnel your WebSocket
>>> connections through another server/class.
>>>
>>> -Nick
>>>

Re: It is a efficient implementation about tunnel in guacamole common project that uses nio

Posted by Mike Jumper <mj...@apache.org>.
Can you provide any specific benchmarks/metrics showing that there is an
appreciable amount of CPU time being spent in thread context switches prior
to the proposed change, and a corresponding improvement after the change is
in place (for the same load)?

- Mike


On Tue, Feb 15, 2022, 22:44 Kurt.Ding <we...@fastonetech.com> wrote:

> Hi Nick
>
> I'm glad to hear from you. Let me answer your questions and then we
> could have a discuss.
>
> Firstly let's assume one user  create hundreds remote connection, then
> in the linux server  which is deployed websocket  container the java
> process creates  hundreds of thread , it cause high cpu usage .
>
> In our production  server(8 core 16g)  ,  we meet  the case dozens of
> users create about 100 remote connections, unfortunately every user
> can't use vnc/ssh smoothly . Then we fix this problem with upgrade our
> server spec
>
> Secondly, as we all knows , many threads running in one server results
> in  thread context switch , and wouldn't increase the number of request
> per second.
>
> I hope this will make sense for you. And Your suggestion about use
> existing classes is a good idea. I will follow your idea and have a try.
>
> I am looking forward to have a discuss with you.
>
> Thanks Kurt
>
> 在 2022/2/15 22:23, Nick Couchman 写道:
> > On Tue, Feb 15, 2022 at 2:11 AM Kurt.Ding <we...@fastonetech.com>
> > wrote:
> >
> >> Hi Guacamole Team
> >>
> >> Was I wrong about this  thread running model? Look forward to your
> reply.
> >>
> >>
> > This is a bit outside my area of expertise, but I guess I'd start by
> asking
> > the following questions:
> > * What actual problem are you trying to solve? What problem is thread
> > creation causing for you? Why is it that you want to limit or reduce the
> > number of threads created? Is reducing the number of threads actually
> going
> > to resolve whatever problem you're concerned about, or is it just going
> to
> > move the problem to another place?
> > * Rather than creating a WebSocket bridge, would it make more sense to
> > integrate your changes into one of the existing classes, perhaps either
> > extending an existing GuacamoleTunnel implementation or just
> implementing a
> > new GuacamoleTunnel that could then be used within the code? That would
> > seem to avoid this extra step of having to tunnel your WebSocket
> > connections through another server/class.
> >
> > -Nick
> >
>

Re: It is a efficient implementation about tunnel in guacamole common project that uses nio

Posted by "Kurt.Ding" <we...@fastonetech.com>.
Hi Nick

I'm glad to hear from you. Let me answer your questions and then we 
could have a discuss.

Firstly let's assume one user  create hundreds remote connection, then 
in the linux server  which is deployed websocket  container the java  
process creates  hundreds of thread , it cause high cpu usage .

In our production  server(8 core 16g)  ,  we meet  the case dozens of 
users create about 100 remote connections, unfortunately every user 
can't use vnc/ssh smoothly . Then we fix this problem with upgrade our 
server spec

Secondly, as we all knows , many threads running in one server results 
in  thread context switch , and wouldn't increase the number of request 
per second.

I hope this will make sense for you. And Your suggestion about use 
existing classes is a good idea. I will follow your idea and have a try.

I am looking forward to have a discuss with you.

Thanks Kurt

在 2022/2/15 22:23, Nick Couchman 写道:
> On Tue, Feb 15, 2022 at 2:11 AM Kurt.Ding <we...@fastonetech.com>
> wrote:
>
>> Hi Guacamole Team
>>
>> Was I wrong about this  thread running model? Look forward to your reply.
>>
>>
> This is a bit outside my area of expertise, but I guess I'd start by asking
> the following questions:
> * What actual problem are you trying to solve? What problem is thread
> creation causing for you? Why is it that you want to limit or reduce the
> number of threads created? Is reducing the number of threads actually going
> to resolve whatever problem you're concerned about, or is it just going to
> move the problem to another place?
> * Rather than creating a WebSocket bridge, would it make more sense to
> integrate your changes into one of the existing classes, perhaps either
> extending an existing GuacamoleTunnel implementation or just implementing a
> new GuacamoleTunnel that could then be used within the code? That would
> seem to avoid this extra step of having to tunnel your WebSocket
> connections through another server/class.
>
> -Nick
>

Re: It is a efficient implementation about tunnel in guacamole common project that uses nio

Posted by Nick Couchman <vn...@apache.org>.
On Tue, Feb 15, 2022 at 2:11 AM Kurt.Ding <we...@fastonetech.com>
wrote:

> Hi Guacamole Team
>
> Was I wrong about this  thread running model? Look forward to your reply.
>
>
This is a bit outside my area of expertise, but I guess I'd start by asking
the following questions:
* What actual problem are you trying to solve? What problem is thread
creation causing for you? Why is it that you want to limit or reduce the
number of threads created? Is reducing the number of threads actually going
to resolve whatever problem you're concerned about, or is it just going to
move the problem to another place?
* Rather than creating a WebSocket bridge, would it make more sense to
integrate your changes into one of the existing classes, perhaps either
extending an existing GuacamoleTunnel implementation or just implementing a
new GuacamoleTunnel that could then be used within the code? That would
seem to avoid this extra step of having to tunnel your WebSocket
connections through another server/class.

-Nick

Re: It is a efficient implementation about tunnel in guacamole common project that uses nio

Posted by "Kurt.Ding" <we...@fastonetech.com>.
Hi Guacamole Team

Was I wrong about this  thread running model? Look forward to your reply.

在 2022/1/26 11:39, Kurt.Ding 写道:
>>> Hi Guacamole Team
>>>
>>>     Our company use guacamole project in remote access service. But 
>>> we found  that every connection always create an new thread for 
>>> listening instructions from guacamole server(lets name it GS ) in
>>>
>>> org.apache.guacamole.websocket.GuacamoleWebSocketTunnelEndpoint#onOpen.
>>>
>>> Our solution write an nio implemention in listening instructions 
>>> then pass  to websocket client, usually in  an broswer. Core idea is 
>>> we create an bridger.  Let's take a further reads .
>>>
>>> When websocket Server  got open connection message, then websocket 
>>> server create an bridger which contains a channel and a websocket 
>>> session.  A channel  use to communicating to GS and websocket 
>>> session use to communicating with websocket client.
>>>
>>> 1. Websocket start to  open Connection
>>>
>>> public BridgeropenConnection(WsSession wsSession, 
>>> GuacamoleConfiguration  configuration) {
>>>     Bridger bridger = createOneBridger(configuration); 
>>> bridger.session = wsSession; try {
>>>        bridger.channel =bridgerBootstrap.connect(); 
>>> //TunnelEndpointNetty.GUACAD_HAND_MAP.put(channel!!.id().toString(), 
>>> this) 
>>> //TunnelEndpointNetty.BROWSER_HAND_MAP.put(session!!.id().toString(), 
>>> this) bridger.sayHello(); }catch (GuacamoleException e) {
>>>        logger.warn("Create tunnel failure ", e); }catch (IOException 
>>> e) {
>>>        logger.warn("Create tunnel failure ", e); }
>>>     // open,send tunnel uuid bridger.sendInstruction(
>>>           new GuacamoleInstruction(
>>>                 GuacamoleTunnel.INTERNAL_DATA_OPCODE, 
>>> bridger.getUUID().toString()
>>>           )
>>>     ); return bridger; }
>>>
>>> 2.  Nio channel connect to guacamole server
>>>
>>> public Channelconnect()throws IOException {
>>>     ChannelFuture f 
>>> =bootstrap.connect(guacdProperties.getHostname(), 
>>> guacdProperties.getPort()); 
>>> f.awaitUninterruptibly(CONNECT_WAIT_TIMEOUT); if (f.isCancelled()) {
>>>        // Connection attempt cancelled by user logger.debug("Connect 
>>> cancelled by client"); }else if (!f.isSuccess()) {
>>>        logger.error("Connect error {}", f.cause().getCause()); }else {
>>>        logger.info("Connect host {} port {} success", 
>>> guacdProperties.getHostname(), guacdProperties.getPort()); return 
>>> f.channel(); }
>>>     throw new IOException("Connection error"); }
>>>
>>> 3. Bridger negotiates args  with guacamole server ,when bridger got 
>>> ready instruction ,Now the bridger has been created and initialized 
>>> success.
>>>
>>> @Override protected void channelRead0(ChannelHandlerContext ctx, 
>>> GuacamoleInstruction msg)throws Exception {
>>>     if (logger.isTraceEnabled()) {
>>>        logger.trace("Get msg from guacad {}", msg); }
>>>     Bridger tunnel = 
>>> WebsocketHandlerAdapter.GUACAD_HAND_MAP.get(ctx.channel().id().toString()); 
>>> //handle guacamole server connect instruction if 
>>> (msg.getOpcode().equals("args")) {
>>>        negotiateArgsThenConnect(ctx,msg,tunnel); }
>>>     if (msg.getOpcode().equals("ready")) {
>>>        receiveGuacamoleReady(ctx,msg,tunnel); }
>>>     tunnel.receiveGuacamoleInstruction(msg); }
>>>
>>> 4. Bridger reveives guacamole instruction then forward it to 
>>> websocket session
>>>
>>> public void receiveGuacamoleInstruction(GuacamoleInstruction ins) {
>>>     try {
>>>        session.sendText(ins.toString()); }catch (IOException e) {
>>>        logger.error("Bridger send msg to error",e); try {
>>>           close(); }catch (IOException ex) {
>>>           logger.error("Bridger send msg to error",ex); }
>>>     }
>>> }
>>>
>>> 5. Bridger receives websocket message then forward it to guacamole 
>>> server
>>>
>>> public void onMessage(String msg) {
>>>     if(logger.isTraceEnabled()){
>>>        logger.info("Send msg to guacd {}",msg); }
>>>     GuacamoleInstruction instruction =null; try {
>>>        instruction =browserDecoder.decode(msg); }catch 
>>> (GuacamoleException e) {
>>>        logger.error("Decoder ws msg error ",e); }
>>>     //handle ws msg by code if 
>>> (instruction.getOpcode().equals(GuacamoleTunnel.INTERNAL_DATA_OPCODE) 
>>> || instruction.getOpcode().equals("nop")) {
>>>
>>>        // Respond to ping requests List<String> args = 
>>> instruction.getArgs(); //ws ping if (args.size() >=2 && 
>>> args.get(0).equals("ping")) {
>>>           try {
>>>              session.sendText(
>>>                    new GuacamoleInstruction(
>>>                          GuacamoleTunnel.INTERNAL_DATA_OPCODE, 
>>> "ping", args.get(1)
>>>                    ).toString()
>>>              ); }catch (IOException e) {
>>>              logger.error("Send msg to ws peer error",e); }
>>>        }
>>>        return; }
>>>
>>>     writeGuacamoleInstruction(instruction); }
>>>
>>> 6. Bridger receives close connection instruction from websocket , 
>>> then close channel and websocket session in bridger
>>>
>>> public void close()throws IOException {
>>>     channel.close(); session.close(); }
>>>
>>> I am looking forward to hearing from you .
>>>
>>> Thanks
>>>
>>> Kurt
>>>