netty做通讯业务,如何做负载?

斗码士 2019-07-26 03:53:14
netty做通讯业务
用netty4.1做通讯客服这一块东西,遇见了一个问题,每一个用户都保存一个长连接
所以把用户的连接用一个这两个Map来存


这如果用nignx负载,这用户连接没办法共享出来了吧,各位大佬时怎么做这一块的?
...全文
365 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
哈希塞特 2019-10-23
  • 打赏
  • 举报
回复
1、连接建立后,服务端会抽象出一个channel对象描述这个连接,收发消息都用到了这个channel对象。这个对象不能序列化到缓存,即使能序列化,再反序列化回来也不能用了。但这个channel肯定对应着一个客户端唯一标识,这个业务上的标识是可以缓存的。而且长连接是有状态的,客户端一旦与服务端某个节点建立连接后,后面通讯都会与这个节点进行。跟无状态的http不一样。
2、服务端如何给某个客户端推送消息。因为只能通过建立连接的那个节点与客户端通讯,所以只能找到那个客户端对应的channel在哪个节点上才能发送消息。可以通过mq来实现,就是所有服务端节点都订阅了同一个主题,服务端将消息往mq投递,需要在消息中带上业务上的客户端唯一标识,这个是可以从缓存中获取的,这样所有服务器节点都会消费到这个消息,然后通过唯一标识来遍历本节点上保存的channel容器,如果对应的channel在本节点上,就可以通过这个channel对象发送消息,不在本节点就不做任何操作。
亲爱的Joe 2019-10-15
  • 打赏
  • 举报
回复
引用 20 楼 斗码士 的回复:
感谢,嗯嗯,我用mq来解决这个了,各服务器之间相互订阅,并且用户注册登录我返回不同的websocket地址,记录对应的websocket在哪个个订阅组里面用mq转到对应的订阅组,再由被转服务器主动推送给用户,这样子
你这样用更好了啊
亲爱的Joe 2019-10-14
  • 打赏
  • 举报
回复
所有长连接的操作都由保存socket的主机来进行,但该主机提供操作接口给客户端或者其他业务主机。 如果要负载均衡,那就需要在单独配置一个主机用来记录各个socket与其所在主机的对应关系。然后当需要获取socket和客户通信时,就先通过记录了socket与所在主机关系的主机获取到socket所在主机,然后将请求转发给对应主机,由对应主机进行socket通信。
maradona1984 2019-10-14
  • 打赏
  • 举报
回复
引用 17 楼 微-凉 的回复:
[quote=引用 11 楼 瘦死的黑骆驼 的回复:] [quote=引用 10 楼 卢囧囧 的回复:] [quote=引用 7 楼 瘦死的黑骆驼 的回复:] [quote=引用 5 楼 卢囧囧 的回复:] 楼上的那位,你说的是单点登录,这里是netty , 你能把stockt放到redis里?
这位同学,我说用redis只是提供一种类似可以共享的解决方案,而且用redis并不意味着是单点登录,单点登录的实现方式也是有多种的。还有就是socket为何不能放在redis里?java对象序列化后都可以转换为字节,想怎么存都行啊,就算转成十六进制字符本地存储都可以的[/quote] 长连接这种如何序列化,长连接一旦建立两头就不能动了,是经历TCP三次握手的,你序列化的只是无意义的一堆数据而已。建议你可以去看看《网络是怎么连接的》这本书,不要再这里瞎说[/quote] 你存到redis里不就是数据吗,什么叫连接建立就不能动了,跟你存数据有关系吗?还有以后不要随便说别人瞎说ok?[/quote] 自己没试过吧,channel不能序列化存储到redis,就算存进去了再取出来也不能用,强行序列化只会报异常,一般存的都是用户id和服务器的对应关系[/quote] 楼上哥们怕是没做过socket相关的开发~
斗码士 2019-10-14
  • 打赏
  • 举报
回复
引用 19 楼 亲爱的Joe 的回复:
所有长连接的操作都由保存socket的主机来进行,但该主机提供操作接口给客户端或者其他业务主机。 如果要负载均衡,那就需要在单独配置一个主机用来记录各个socket与其所在主机的对应关系。然后当需要获取socket和客户通信时,就先通过记录了socket与所在主机关系的主机获取到socket所在主机,然后将请求转发给对应主机,由对应主机进行socket通信。
感谢,嗯嗯,我用mq来解决这个了,各服务器之间相互订阅,并且用户注册登录我返回不同的websocket地址,记录对应的websocket在哪个个订阅组里面用mq转到对应的订阅组,再由被转服务器主动推送给用户,这样子
微-凉 2019-10-13
  • 打赏
  • 举报
回复
引用 11 楼 瘦死的黑骆驼 的回复:
[quote=引用 10 楼 卢囧囧 的回复:]
[quote=引用 7 楼 瘦死的黑骆驼 的回复:]
[quote=引用 5 楼 卢囧囧 的回复:]
楼上的那位,你说的是单点登录,这里是netty , 你能把stockt放到redis里?

这位同学,我说用redis只是提供一种类似可以共享的解决方案,而且用redis并不意味着是单点登录,单点登录的实现方式也是有多种的。还有就是socket为何不能放在redis里?java对象序列化后都可以转换为字节,想怎么存都行啊,就算转成十六进制字符本地存储都可以的[/quote]

长连接这种如何序列化,长连接一旦建立两头就不能动了,是经历TCP三次握手的,你序列化的只是无意义的一堆数据而已。建议你可以去看看《网络是怎么连接的》这本书,不要再这里瞎说[/quote]
你存到redis里不就是数据吗,什么叫连接建立就不能动了,跟你存数据有关系吗?还有以后不要随便说别人瞎说ok?[/quote]

自己没试过吧,channel不能序列化存储到redis,就算存进去了再取出来也不能用,强行序列化只会报异常,一般存的都是用户id和服务器的对应关系
瘦死的黑骆驼 2019-08-02
  • 打赏
  • 举报
回复
引用 10 楼 卢囧囧 的回复:
[quote=引用 7 楼 瘦死的黑骆驼 的回复:] [quote=引用 5 楼 卢囧囧 的回复:] 楼上的那位,你说的是单点登录,这里是netty , 你能把stockt放到redis里?
这位同学,我说用redis只是提供一种类似可以共享的解决方案,而且用redis并不意味着是单点登录,单点登录的实现方式也是有多种的。还有就是socket为何不能放在redis里?java对象序列化后都可以转换为字节,想怎么存都行啊,就算转成十六进制字符本地存储都可以的[/quote] 长连接这种如何序列化,长连接一旦建立两头就不能动了,是经历TCP三次握手的,你序列化的只是无意义的一堆数据而已。建议你可以去看看《网络是怎么连接的》这本书,不要再这里瞎说[/quote] 你存到redis里不就是数据吗,什么叫连接建立就不能动了,跟你存数据有关系吗?还有以后不要随便说别人瞎说ok?
瘦死的黑骆驼 2019-08-02
  • 打赏
  • 举报
回复
或者把你需要的数据从这几个对象中取出来,封装到新的类里面也可以啊
瘦死的黑骆驼 2019-08-02
  • 打赏
  • 举报
回复
自己封装一个类实现Serializable接口,把这些对象当成属性封装进去
斗码士 2019-08-02
  • 打赏
  • 举报
回复
引用 13 楼 瘦死的黑骆驼 的回复:
[quote=引用 12 楼 斗码士 的回复:] [quote=引用 11 楼 瘦死的黑骆驼 的回复:] [quote=引用 10 楼 卢囧囧 的回复:] [quote=引用 7 楼 瘦死的黑骆驼 的回复:] [quote=引用 5 楼 卢囧囧 的回复:] 楼上的那位,你说的是单点登录,这里是netty , 你能把stockt放到redis里?
这位同学,我说用redis只是提供一种类似可以共享的解决方案,而且用redis并不意味着是单点登录,单点登录的实现方式也是有多种的。还有就是socket为何不能放在redis里?java对象序列化后都可以转换为字节,想怎么存都行啊,就算转成十六进制字符本地存储都可以的[/quote] 长连接这种如何序列化,长连接一旦建立两头就不能动了,是经历TCP三次握手的,你序列化的只是无意义的一堆数据而已。建议你可以去看看《网络是怎么连接的》这本书,不要再这里瞎说[/quote] 你存到redis里不就是数据吗,什么叫连接建立就不能动了,跟你存数据有关系吗?还有以后不要随便说别人瞎说ok?[/quote] 我也试过序列化之后存到redis,但是netty长连接对象好像没办法序列化[/quote] 序列化对象需要实现Serializable接口,可能你的那个对象应该没有实现这个接口吧,你可以自己重新封装一下[/quote] import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; 这种没有办法序列化
瘦死的黑骆驼 2019-08-02
  • 打赏
  • 举报
回复
引用 12 楼 斗码士 的回复:
[quote=引用 11 楼 瘦死的黑骆驼 的回复:] [quote=引用 10 楼 卢囧囧 的回复:] [quote=引用 7 楼 瘦死的黑骆驼 的回复:] [quote=引用 5 楼 卢囧囧 的回复:] 楼上的那位,你说的是单点登录,这里是netty , 你能把stockt放到redis里?
这位同学,我说用redis只是提供一种类似可以共享的解决方案,而且用redis并不意味着是单点登录,单点登录的实现方式也是有多种的。还有就是socket为何不能放在redis里?java对象序列化后都可以转换为字节,想怎么存都行啊,就算转成十六进制字符本地存储都可以的[/quote] 长连接这种如何序列化,长连接一旦建立两头就不能动了,是经历TCP三次握手的,你序列化的只是无意义的一堆数据而已。建议你可以去看看《网络是怎么连接的》这本书,不要再这里瞎说[/quote] 你存到redis里不就是数据吗,什么叫连接建立就不能动了,跟你存数据有关系吗?还有以后不要随便说别人瞎说ok?[/quote] 我也试过序列化之后存到redis,但是netty长连接对象好像没办法序列化[/quote] 序列化对象需要实现Serializable接口,可能你的那个对象应该没有实现这个接口吧,你可以自己重新封装一下
斗码士 2019-08-02
  • 打赏
  • 举报
回复
引用 11 楼 瘦死的黑骆驼 的回复:
[quote=引用 10 楼 卢囧囧 的回复:] [quote=引用 7 楼 瘦死的黑骆驼 的回复:] [quote=引用 5 楼 卢囧囧 的回复:] 楼上的那位,你说的是单点登录,这里是netty , 你能把stockt放到redis里?
这位同学,我说用redis只是提供一种类似可以共享的解决方案,而且用redis并不意味着是单点登录,单点登录的实现方式也是有多种的。还有就是socket为何不能放在redis里?java对象序列化后都可以转换为字节,想怎么存都行啊,就算转成十六进制字符本地存储都可以的[/quote] 长连接这种如何序列化,长连接一旦建立两头就不能动了,是经历TCP三次握手的,你序列化的只是无意义的一堆数据而已。建议你可以去看看《网络是怎么连接的》这本书,不要再这里瞎说[/quote] 你存到redis里不就是数据吗,什么叫连接建立就不能动了,跟你存数据有关系吗?还有以后不要随便说别人瞎说ok?[/quote] 我也试过序列化之后存到redis,但是netty长连接对象好像没办法序列化
斗码士 2019-08-01
  • 打赏
  • 举报
回复
引用
7
同学,Netty这种长连接,我不知道要怎么序列化连接对象?知到怎么序列化我这问题就解决了,求教
卢囧囧 2019-08-01
  • 打赏
  • 举报
回复
引用 7 楼 瘦死的黑骆驼 的回复:
[quote=引用 5 楼 卢囧囧 的回复:] 楼上的那位,你说的是单点登录,这里是netty , 你能把stockt放到redis里?
这位同学,我说用redis只是提供一种类似可以共享的解决方案,而且用redis并不意味着是单点登录,单点登录的实现方式也是有多种的。还有就是socket为何不能放在redis里?java对象序列化后都可以转换为字节,想怎么存都行啊,就算转成十六进制字符本地存储都可以的[/quote] 长连接这种如何序列化,长连接一旦建立两头就不能动了,是经历TCP三次握手的,你序列化的只是无意义的一堆数据而已。建议你可以去看看《网络是怎么连接的》这本书,不要再这里瞎说
瘦死的黑骆驼 2019-08-01
  • 打赏
  • 举报
回复
序列化对象转换成字节就行了,然后可以把字节反序列化转换成对象 序列化:

byte[] bytes = null;      
        ByteArrayOutputStream bos = new ByteArrayOutputStream();      
        try {        
            ObjectOutputStream oos = new ObjectOutputStream(bos);         
            oos.writeObject(obj);        
            oos.flush();         
            bytes = bos.toByteArray ();      
            oos.close();         
            bos.close();        
        } catch (IOException ex) {        
            ex.printStackTrace();   
        }
反序列化:

Object obj = null;      
        try {        
            ByteArrayInputStream bis = new ByteArrayInputStream (bytes);        
            ObjectInputStream ois = new ObjectInputStream (bis);        
            obj = ois.readObject();      
            ois.close();   
            bis.close();   
        } catch (IOException ex) {        
            ex.printStackTrace();   
        } catch (ClassNotFoundException ex) {        
            ex.printStackTrace();   
        }
后面的代码是百度出来的,没有自己去写了,见谅
瘦死的黑骆驼 2019-07-31
  • 打赏
  • 举报
回复
引用 5 楼 卢囧囧 的回复:
楼上的那位,你说的是单点登录,这里是netty , 你能把stockt放到redis里?
这位同学,我说用redis只是提供一种类似可以共享的解决方案,而且用redis并不意味着是单点登录,单点登录的实现方式也是有多种的。还有就是socket为何不能放在redis里?java对象序列化后都可以转换为字节,想怎么存都行啊,就算转成十六进制字符本地存储都可以的
maradona1984 2019-07-30
  • 打赏
  • 举报
回复
引用 5 楼 卢囧囧 的回复:
楼上的那位,你说的是单点登录,这里是netty , 你能把stockt放到redis里?
存的东西肯定不是channel,而是用户所在服务器的信息,但这个方案也存在很多问题 我们的做法就粗暴了,nginx做负载,发消息到客户端的请求会调用所有的netty服务器,如果服务器上存在该用户的连接就发送,不存在就不发,这样牺牲部分性能,减轻代码的复杂度
卢囧囧 2019-07-30
  • 打赏
  • 举报
回复
楼上的那位,你说的是单点登录,这里是netty , 你能把stockt放到redis里?
瘦死的黑骆驼 2019-07-30
  • 打赏
  • 举报
回复
采用第三方中间件比如redis,把你的用户信息存入nosql db中,这样就可以所有的服务器能共享了
卢囧囧 2019-07-30
  • 打赏
  • 举报
回复
同时负载均衡服务器要保存用户和服务器的对应关系
加载更多回复(2)

81,094

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧