全国首批9所重点马院网站建设,牡丹江市住房和城乡建设局网站,go 语言 做网站,做网站公司哪家正规短连接 VS 长连接
什么是短连接
客户端和服务器每进行一次HTTP操作#xff0c;就建立一次连接#xff0c;任务结束就中断连接。
长连接
客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭#xff0c;客户端再次访问这个服务器时#xff0c;会继续使用这一条已经建立…短连接 VS 长连接
什么是短连接
客户端和服务器每进行一次HTTP操作就建立一次连接任务结束就中断连接。
长连接
客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭客户端再次访问这个服务器时会继续使用这一条已经建立的连接。
长连接的好处
假如请求一个普通的网页 但是这个网页有很多个 css js请求 那每次打开一个网页基本就要建立几个甚至几十个TCP连接浪费很多网络资源。如果是长连接的话那么这么多HTTP请求包括请求网页的内容、CSS文件、JS文件、图片等都是使用的一个TCP连接显然可以节省很多资源。
另外一点长连接并不是永久连接的。如果一段时间内具体时间可以在header中进行设置也就是所谓的超时时间这个连接没有HTTP请求发出的话那么这个长连接就会被断掉。
短轮询VS 长轮询
什么是轮询
就比如在飞机上想上厕所 却发现厕所有人需要等待 但是你又不想在那等 就只能回去等 但是过一段时间在去 还有人 在接着回去 这么周而复始的去回
短轮询
轮询的原理就是客户端以一定的时间间隔向服务端发出请求频繁的请求保持客户端和服务端同步。 短轮询最大的问题就是客户端发出请求和服务器端的更新并不是一致的。客户端以固定的频率想服务器发出请求可能服务器端并没有更新返回的是个空的信息等服务器端更新的时候有可能客户端并没有请求而且只有最后一次请求才能获得最新数据这样多次请求不仅浪费了资源而且并不是实际上的实时更新。
优缺点
优点后端程序编写比较容易 缺点请求中有大半是无用浪费带宽和服务器资源。而每一次的 HTTP 请求和应答都带有完整的 HTTP 头信息这就增加了每次传输的数据量
长轮询
页面发起一个到服务器的请求然后服务器一直保持连接打开直到有数据可以发送。 发送完数据之后浏览器关闭连接随即又发送一个到服务器的新请求。这一过程在页面打开期间一直持续不断。在服务端hold住Http请求死循环或者sleep等等方式等到目标时间发生返回Http响应。
长轮询优缺点
优点在无消息的情况下不会频繁的请求节省了网络流量解决了服务端一直疲于接受请求的窘境。 缺点服务器hold连接会消耗资源需要同时维护多个线程服务器所能承载的TCP连接数是有上限的这种轮询很容易把连接数顶满。
Nacos是怎么处理服务配置修改刷新
1.X版本 客户端启动的时候会初始化一个长连接的线程池定时去 发送pull请求 会发送一个HTTP请求到服务端 在服务端hold住Http请求 超时时间是30秒 30s内 有可能触发变化 push数据到客户端 30s内 数据没有变更超时返回
缺点
30 秒定期创建销毁连接GC压力大
2.X版本
Nacos 2.x 相比上面 30s ⼀次的长轮训升级成长链接模式配置变更启动建立长链接配置变 更服务端推送变更配置列表然后 SDK 拉取配置更新因此通信效率大幅提升
Nacos长连接源码解析
这里只抓重点 想看详情的话看前面几章
客户端变更推送配置变更事件 /*** adaptor to config module ,when server side config change ,invoke this method.** param groupKey groupKey*/public void configDataChanged(String groupKey, String dataId, String group, String tenant, boolean isBeta,ListString betaIps, String tag) {//获取注册的Client列表SetString listeners configChangeListenContext.getListeners(groupKey);if (CollectionUtils.isEmpty(listeners)) {return;}int notifyClientCount 0;//遍历client列表for (final String client : listeners) {//拿到grpc连接Connection connection connectionManager.getConnection(client);if (connection null) {continue;}ConnectionMeta metaInfo connection.getMetaInfo();//beta ips check.String clientIp metaInfo.getClientIp();String clientTag metaInfo.getTag();if (isBeta betaIps ! null !betaIps.contains(clientIp)) {continue;}//tag checkif (StringUtils.isNotBlank(tag) !tag.equals(clientTag)) {continue;}//构建请求参数ConfigChangeNotifyRequest notifyRequest ConfigChangeNotifyRequest.build(dataId, group, tenant);//构建推送任务RpcPushTask rpcPushRetryTask new RpcPushTask(notifyRequest, 50, client, clientIp, metaInfo.getAppName());//推送任务 向客户端发送变更通知push(rpcPushRetryTask);notifyClientCount;}Loggers.REMOTE_PUSH.info(push [{}] clients ,groupKey[{}], notifyClientCount, groupKey);}
ClientWorker 这里最终会调用 notifyListenConfig方法 这个方法实际上就是往listenExecutebell这个阻塞队列中去offer一个object对象 private void initRpcClientHandler(final RpcClient rpcClientInner) {rpcClientInner.registerServerRequestHandler((request) - {if (request instanceof ConfigChangeNotifyRequest) {ConfigChangeNotifyRequest configChangeNotifyRequest (ConfigChangeNotifyRequest) request;LOGGER.info([{}] [server-push] config changed. dataId{}, group{},tenant{},rpcClientInner.getName(), configChangeNotifyRequest.getDataId(),configChangeNotifyRequest.getGroup(), configChangeNotifyRequest.getTenant());String groupKey GroupKey.getKeyTenant(configChangeNotifyRequest.getDataId(), configChangeNotifyRequest.getGroup(),configChangeNotifyRequest.getTenant());CacheData cacheData cacheMap.get().get(groupKey);if (cacheData ! null) {synchronized (cacheData) {cacheData.getLastModifiedTs().set(System.currentTimeMillis());cacheData.setSyncWithServer(false);//向阻塞队列中添加元素 触发长连接的执行notifyListenConfig();}}//返回客户端响应return new ConfigChangeNotifyResponse();}return null;});}
客户端处理变更事件
客户端启动的时候会创建 NaocsConfigService 他的构造方法中会创建一个ClientWorker并启动 然后会执行 startInternal方法 这个方法中会看到 从listenExecutebell中拿数据 listenExecutebell在上文服务配置发生变更的时候会往里面塞一个object 对象 所以这里就能poll队列中出来 如果队列为空等待5秒后执行如果队列不为空立即执行 Overridepublic void startInternal() {executor.schedule(() - {while (!executor.isShutdown() !executor.isTerminated()) {try {listenExecutebell.poll(5L, TimeUnit.SECONDS);if (executor.isShutdown() || executor.isTerminated()) {continue;}executeConfigListen();} catch (Exception e) {LOGGER.error([ rpc listen execute ] [rpc listen] exception, e);}}}, 0L, TimeUnit.MILLISECONDS);}executeConfigListen 方法详细看 https://blog.csdn.net/qq_41956309/article/details/134904263这段 下面简述一下 其实就是将3000个配置信息封装成一个CacheData 共用一个TaskId 一个TaskId 对应一个Client连接 然后会发送到服务端 通过比较md5的方式来判断哪些配置发生了变更 然后会返回变更的key 然后客户端遍历返回的有变更信息的key的信息 在去调用服务端查找具体的配置信息 返回客户端然后做返回和动态刷新以及本地缓存的修改