青海建设协会网站,wordpress邮箱修改,手机网站程序下载,重庆网站建设去迅法网目录 1、前言1.1、方法一1.2、方法二 2、方案二实战2.1、在netty服务里加上ws连接、中断事件2.2、在netty服务里加上消息服务 4、总结 使用Springboot netty 打造聊天服务系列文章 第一章 初始搭建工程 第二章 Nacos集群问题记录 1、前言
在使用Springboot Nacos Netty(Web… 目录 1、前言1.1、方法一1.2、方法二 2、方案二实战2.1、在netty服务里加上ws连接、中断事件2.2、在netty服务里加上消息服务 4、总结 使用Springboot netty 打造聊天服务系列文章 第一章 初始搭建工程 第二章 Nacos集群问题记录 1、前言
在使用Springboot Nacos Netty(WebSocket) 集群后发现了一个问题。 在集群环境下 X用户已经连接上了集群中的A服务器这时Y用户发送给X用户的消息在B服务器那么此时的消息应该如何处理呢
1.1、方法一
通过广播的模式把消息发送到MQ且带有netty的channelIdnetty集群的服务都订阅这个MQ。 通过对比channelId不存在channelId的丢弃消息不处理。存在channelId的服务处理此消息并通过channel把消息推送给X用户。
1.2、方法二
发消息时去寻找对应用户X的channel。 1、从缓存里获取用户X对应的channelId等信息首先判断是否在缓存里如果没有即用户X不在线用户X下次连接netty服务时再去推送消息 2、如果缓存里有判断此channel是否在当前服务中 首先判断当前服务里是否有用户X对应的channelId如果有直接通过channel发送消息给用户X 3、如果没有则去组装IP、端口去调用此服务的消息服务去发送消息。
2、方案二实战
方案一非常简单订阅MQ即可实现网上案例大多基于此。 我们今天重点讲解方案二在netty服务里加入消息服务后续通过匹配用户X的channel去发送消息
2.1、在netty服务里加上ws连接、中断事件
在ws连接时本地服务器加入channelId、channel的缓存 同时把channelId、本机IP、本机端口放入redis缓存供远程消息服务调用。
2.2、在netty服务里加上消息服务
1、通过传递来的channelId从缓存里找到对应的服务IP、端口 2、调用对应的消息服务IP、端口加上消息服务的地址 3、消息服务里铜鼓 import cn.hutool.core.bean.BeanUtil;
import com.qhkj.nettychatserver.bean.domain.Message;
import com.qhkj.nettychatserver.bean.request.MessageRequest;
import com.qhkj.nettychatserver.config.NettyConfig;
import com.qhkj.nettychatserver.config.http.HttpResult;
import com.qhkj.nettychatserver.config.http.HttpResultGenerator;
import com.qhkj.nettychatserver.config.http.HttpStatusEnum;
import com.qhkj.nettychatserver.constant.Common;
import com.qhkj.nettychatserver.constant.NettyCommon;
import com.qhkj.nettychatserver.netty.NettyHandler;
import com.qhkj.nettychatserver.service.MessageService;
import com.qhkj.nettychatserver.util.RedisUtil;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import com.qhkj.nettychatserver.bean.request.NettyMesaage;
import com.qhkj.nettychatserver.service.NettyService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;Slf4j
Service(chat)
public class ChatNettyServiceImpl implements NettyService {Resourceprivate MessageService messageService;Resourceprivate NettyConfig nettyConfig;Resourceprivate RedisUtil redisUtil;Resourceprivate RestTemplate restTemplate;// 确定channel之后发送消息private void nettyHandler(NettyMesaage message, Channel channel) {log.info(message- channelId:{} , nettyName: {}, channel.id(), nettyConfig.getNettyServerName());Date now new Date();Message dbmsg Message.builder().messageId(NettyCommon.getIdWorker().nextId()).createTime(now).modifyTime(now).build();BeanUtil.copyProperties(message, dbmsg, Common.options);boolean flag messageService.insertOne(dbmsg);if (flag) {channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(HttpResultGenerator.success(nettyConfig.getNettyServerName()))));} else {channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(HttpResultGenerator.fail(HttpStatusEnum.INTERNAM_SERVER_ERROR.getCode(), nettyConfig.getNettyServerName() ))));}}Overridepublic HttpResult nettyHandler(MessageRequest request) {NettyMesaage nettyMesaage new MessageRequest();BeanUtil.copyProperties(request, nettyMesaage);String serverInfo (String) redisUtil.get(request.getChannelId());if(StringUtils.isEmpty(serverInfo)) {log.info(用户不在线!);return HttpResultGenerator.success(用户不在线!);}Channel channel NettyHandler.channelMap.get(request.getChannelId());// 本机与用户有连接if(null ! channel) {this.nettyHandler(nettyMesaage, channel);} else {String url http:// serverInfo /msg/send;HashMap jsonObject restTemplate.postForObject(url, request, HashMap.class);if( !jsonObject.get(code).equals(200) ) {log.info(消息发送失败!);return HttpResultGenerator.fail(HttpStatusEnum.SERVER_BUSY.getCode(),消息发送失败);}}return HttpResultGenerator.success(消息发送成功!);}
}
4、总结
文章写完之后发现第二种方法问题特别多需要在用户上下线ws连接、掉线、netty服务销毁等时使用缓存记录用户与服务器的关系。在消息发送给接收方时从缓存里取出接收方服务器信息通过接收方服务器通知接收方有新消息。
最后给出2张消息服务架构简图 1、集群版
2、单机版 分析单机版客户端和netty之间的压力是相当小万人同时在线人均每秒2条消息所需带宽也仅仅接近2MB对应的内存消耗也是非常之小几乎也是毫无压力。理论上来说netty单机10MB带宽、100MB内存就可以支撑5万用户当然还得维护在线用户channel池、写数据到消息队列等等消耗支撑2万在线用户肯定是没问题。
而与之配套的数据服务系统获取数据、解析消息并存库等就可以做成集群分配更大内存、更多的机器去支撑快速增长的用户。