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
>>>