精华内容
下载资源
问答
  • 一:百万用户的websocket的技术瓶颈 主要有三个:内核瓶颈、cpu瓶颈和锁瓶颈 1内核瓶颈 在线用户达百万时,实时数据量非常之大,linux内核发送tcp的极限包频率是100万/秒, 优化:消息合并,减小网络小包推送,...

    整理自https://www.imooc.com/learn/1025,GO实现千万级WebSocket消息推送服务

    一:百万用户的websocket的技术瓶颈

    主要有三个:内核瓶颈、cpu瓶颈和锁瓶颈

    1内核瓶颈

    在线用户达百万时,实时数据量非常之大,linux内核发送tcp的极限包频率是100万/秒,

    优化:消息合并,减小网络小包推送,同一秒内的多条消息合并成1条推送,减小内核压力

    2 cpu 瓶颈

    1)浏览器与服务器通常采取json格式通讯

    2)json编码特别消耗cpu资源

    3)向100万在线推送资源,json需要100万次encode

    优化:编码前置:1次编码+100万次推送

    3.锁瓶颈

    1)需要维护在线用户(100万在线),通常是个哈希字典结构

    2)推送消息遍历整个集合,顺序发送消息,耗时极长

    3)推送期间,客户端正常上下线,集合面临不停的修改,需要上锁,这期间客户端拿不到锁会无法正常上下线

    解决方案:

    a)大锁拆小,把长连接打散到多个集合,每个集合有自己的锁,每个集合独立,锁之间没竞争关系,

    可多线程并发推送不同的集合

    b)读写锁代替互斥锁

    二 单机瓶颈

    维护海量长连接会花费不少的内存

    消息推送瞬时会消耗大量的cpu资源

    消息推送瞬时带宽高达400-600MB(4-6Gbits)万兆网卡才能满足需求,是主要的技术瓶颈

    因此需要分布式架构

     

     

    展开全文
  • WebSocket

    2016-01-12 20:30:52
    WebSocket 前世今生 众所周知,Web 应用的交互过程通常是客户端通过浏览器发出一个请求,服务器端接收请求后进行处理并返回结果给客户端,客户端浏览器将信息呈现,这种机制对于信息变化不是特别频繁的应用尚可...

    部分资源来源于IBM http://www.ibm.com/developerworks/cn/java/j-lo-WebSocket/

    WebSocket 前世今生

    众所周知,Web 应用的交互过程通常是客户端通过浏览器发出一个请求,服务器端接收请求后进行处理并返回结果给客户端,客户端浏览器将信息呈现,这种机制对于信息变化不是特别频繁的应用尚可,但对于实时要求高、海量并发的应用来说显得捉襟见肘,尤其在当前业界移动互联网蓬勃发展的趋势下,高并发与用户实时响应是 Web 应用经常面临的问题,比如金融证券的实时信息,Web 导航应用中的地理位置获取,社交网络的实时消息推送等。

    传统的请求-响应模式的 Web 开发在处理此类业务场景时,通常采用实时通讯方案,常见的是:

    • 轮询,原理简单易懂,就是客户端通过一定的时间间隔以频繁请求的方式向服务器发送请求,来保持客户端和服务器端的数据同步。问题很明显,当客户端以固定频率向服务器端发送请求时,服务器端的数据可能并没有更新,带来很多无谓请求,浪费带宽,效率低下。
    • 基于 Flash,AdobeFlash 通过自己的 Socket 实现完成数据交换,再利用 Flash 暴露出相应的接口为 JavaScript 调用,从而达到实时传输目的。此方式比轮询要高效,且因为 Flash 安装率高,应用场景比较广泛,但在移动互联网终端上 Flash 的支持并不好。IOS 系统中没有 Flash 的存在,在 Android 中虽然有 Flash 的支持,但实际的使用效果差强人意,且对移动设备的硬件配置要求较高。2012 年 Adobe 官方宣布不再支持 Android4.1+系统,宣告了 Flash 在移动终端上的死亡。

    从上文可以看出,传统 Web 模式在处理高并发及实时性需求的时候,会遇到难以逾越的瓶颈,我们需要一种高效节能的双向通信机制来保证数据的实时传输。在此背景下,基于 HTML5 规范的、有 Web TCP 之称的 WebSocket 应运而生。

    早期 HTML5 并没有形成业界统一的规范,各个浏览器和应用服务器厂商有着各异的类似实现,如 IBM 的 MQTT,Comet 开源框架等,直到 2014 年,HTML5 在 IBM、微软、Google 等巨头的推动和协作下终于尘埃落地,正式从草案落实为实际标准规范,各个应用服务器及浏览器厂商逐步开始统一,在 JavaEE7 中也实现了 WebSocket 协议,从而无论是客户端还是服务端的 WebSocket 都已完备,读者可以查阅HTML5 规范,熟悉新的 HTML 协议规范及 WebSocket 支持。

    WebSocket 机制

    以下简要介绍一下 WebSocket 的原理及运行机制。

    WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:

    • WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;
    • WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信。

    非 WebSocket 模式传统 HTTP 客户端与服务器的交互如下图所示:

    图 1. 传统 HTTP 请求响应客户端服务器交互图
    图 1. 传统 HTTP 请求响应客户端服务器交互图

    使用 WebSocket 模式客户端与服务器的交互如下图:

    图 2.WebSocket 请求响应客户端服务器交互图
    图 2.WebSocket 请求响应客户端服务器交互图

    上图对比可以看出,相对于传统 HTTP 每次请求-应答都需要客户端与服务端建立连接的模式,WebSocket 是类似 Socket 的 TCP 长连接的通讯模式,一旦 WebSocket 连接建立后,后续数据都以帧序列的形式传输。在客户端断开 WebSocket 连接或 Server 端断掉连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实时性优势明显。


    WebSocket 注意

    1. websocket是TCP的长连接,所以,一定要注意服务器的Timeout和数据库连接的Timeout。


    展开全文
  • 实现私聊和群聊两个功能,要在web端实现想微信QQ那样的即时通讯的功能,我们需要了解一下websocketwebsocket是一种可以双向通讯的长连接协议,http是获取完数据就关闭,websocket则可以一直连接,就像铺了一条管道...

    700456ca5ec4cfcb88a9efd3ae7621f4.png

    实现私聊和群聊两个功能,要在web端实现想微信QQ那样的即时通讯的功能,我们需要了解一下websocket。

    websocket是一种可以双向通讯的长连接协议,http是获取完数据就关闭,websocket则可以一直连接,就像铺了一条管道一样,水可以一直流着。

    一、websocket前端

    var ws = new WebSocket("ws://127.0.0.1.com:8282");
        ws.onopen=function(){
            var msg = JSON.stringify({
                type: "login",
                content: "login"
            });
            ws.send(msg);
        }
        
        ws.onmessage = function (e){ 
            console.log(e);
            //服务器发送的内容
            var res = JSON.parse(e.data);
            switch(res.type){
                case "login":
                    
                    break;
                case "pm":
                    
                    break;
                case "groupPm":
                    
                    break;
                    
            }
        }
        ws.onerror=function (e){ 
            console.log(e);
        }
        ws.onclose=function (e){ 
            console.log(e);
        }
    

    二、服务端

    7207899fb0051021b3bfa07965e7f2bf.png


    客户端发送http请求,带上Sec-WebSocket-Key,
    服务端握手 加密key,发送给客户端。
    双方能进行交流。

    发送接收消息需要进行打包encode 解包decode。

    <?php
    
    class SocketService
    {
        public $host="tcp://0.0.0.0:8000";
        private $address;
        private $port;
        private $_sockets;
        public $clients;
        public $maxid=1000;
        public function __construct($address = '', $port='')
        {
                if(!empty($address)){
                    $this->address = $address;
                }
                if(!empty($port)) {
                    $this->port = $port;
                }
        }
        
        public function onConnect($client_id){
            echo  "Client client_id:{$client_id}   n";
             
        }
        
        public function onMessage($client_id,$msg){
            //发给所有的
            foreach($this->clients as $kk=>$cc){
                if($kk>0){
                    $this->send($cc, $msg);
                }                                
            }    
        }
        
        public function onClose($client_id){
            echo "$client_id close n";
        }
        
        public function service(){
            //获取tcp协议号码。
            $tcp = getprotobyname("tcp");
            $sock = stream_socket_server($this->host, $errno, $errstr);;
            
            if(!$sock)
            {
                throw new Exception("failed to create socket: ".socket_strerror($sock)."n");
            }
            stream_set_blocking($sock,0);
            $this->_sockets = $sock;
             echo "listen on $this->address $this->host ... n";
        }
     
        public function run(){
            $this->service();
            $this->clients[] = $this->_sockets;
            while (true){
                $changes = $this->clients;
                //$write = NULL;
                //$except = NULL;
                stream_select($changes,  $write,  $except, NULL);
                foreach ($changes as $key => $_sock){
                    if($this->_sockets == $_sock){ //判断是不是新接入的socket
                        if(($newClient = stream_socket_accept($_sock))  === false){
                            unset($this->clients[$key]);
                            continue;
                        }
                        $line = trim(stream_socket_recvfrom($newClient, 1024));
                        //握手
                        $this->handshaking($newClient, $line);
                        $this->maxid++;
                        $this->clients[$this->maxid] = $newClient;
                        $this->onConnect($this->maxid);
                    } else {
                        $res=@stream_socket_recvfrom($_sock,  2048);
                        //客户端主动关闭
                        if(strlen($res) < 9) {
                            stream_socket_shutdown($this->clients[$key],STREAM_SHUT_RDWR);
                            unset($this->clients[$key]);
                            $this->onClose($key);
                        }else{
                            //解密
                            $msg = $this->decode($res);
                            $this->onMessage($key,$msg);
                        }
                         
                        
                    }
                }
            }
        }
     
        /**
         * 握手处理
         * @param $newClient socket
         * @return int  接收到的信息
         */
        public function handshaking($newClient, $line){
     
            $headers = array();
            $lines = preg_split("/rn/", $line);
            foreach($lines as $line)
            {
                $line = chop($line);
                if(preg_match('/A(S+): (.*)z/', $line, $matches))
                {
                    $headers[$matches[1]] = $matches[2];
                }
            }
            $secKey = $headers['Sec-WebSocket-Key'];
            $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
            $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshakern" .
                "Upgrade: websocketrn" .
                "Connection: Upgradern" .
                "WebSocket-Origin: $this->addressrn" .
                "WebSocket-Location: ws://$this->address:$this->port/websocket/websocketrn".
                "Sec-WebSocket-Accept:$secAcceptrnrn";
            return stream_socket_sendto($newClient, $upgrade);
        }
        
        
        
        
        /**
         * 发送数据
         * @param $newClinet 新接入的socket
         * @param $msg   要发送的数据
         * @return int|string
         */
        public function send($newClinet, $msg){
            $msg = $this->encode($msg);
            stream_socket_sendto($newClinet, $msg);
        }
        /**
         * 解析接收数据
         * @param $buffer
         * @return null|string
         */
        public function decode($buffer){
            $len = $masks = $data = $decoded = null;
            $len = ord($buffer[1]) & 127;
            if ($len === 126)  {
                $masks = substr($buffer, 4, 4);
                $data = substr($buffer, 8);
            } else if ($len === 127)  {
                $masks = substr($buffer, 10, 4);
                $data = substr($buffer, 14);
            } else  {
                $masks = substr($buffer, 2, 4);
                $data = substr($buffer, 6);
            }
            for ($index = 0; $index < strlen($data); $index++) {
                $decoded .= $data[$index] ^ $masks[$index % 4];
            }
            return $decoded;
        }
     
        
        /**
        *打包消息
        **/
         public function encode($buffer) {
            $first_byte="x81";
            $len=strlen($buffer);
            if ($len <= 125) {
                $encode_buffer = $first_byte . chr($len) . $buffer;
            } else {
                if ($len <= 65535) {
                    $encode_buffer = $first_byte . chr(126) . pack("n", $len) . $buffer;
                } else {
                    $encode_buffer = $first_byte . chr(127) . pack("xxxxN", $len) . $buffer;
                }
            }
            return $encode_buffer;
        }
     
        /**
         * 关闭socket
         */
        public function close(){
            return socket_close($this->_sockets);
        }
    }
     
    $sock = new SocketService('127.0.0.1','9000');
    $sock->run();
    

    三、常见应用

    1.聊天室、群聊 实现类似QQ群的web版本

    http://2.im私聊、客服 实现类似qq聊天,和即时客服交流

    3.消息推送 建立即时的web消息推送

    以上内容希望帮助到大家,需要更多文章可以关注公众号:PHP从入门到精通,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些PHP高级、架构视频资料和大厂PHP面试PDF免费获取,需要戳这里PHP进阶架构师>>>实战视频、大厂面试文档免费获取

    展开全文
  • Websocket

    2019-12-08 20:09:08
    传统的Web模式在处理高并发及实时性需求的时候,会遇到难以逾越的瓶颈,需要一种高效节能的双向通信机制来保证数据的实时传输。在此背景下,基于HTML5规范的、有Web TCP之称的 WebSocket应运而生。早期HTML5并没有...

    众所周知,Web应用的通信过程通常是客户端通过浏览器发出一个请求,服务器端接收请求后进行处理并返回结果给客户端,客户端浏览器将信息呈现。这种机制对于信息变化不是特别频繁的应用可以良好支撑,但对于实时要求高、海量并发的应用来说显得捉襟见肘,尤其在当前业界移动互联网蓬勃发展的趋势下,高并发与用户实时响应是Web应用经常面临的问题,比如金融证券的实时信息、Web导航应用中的地理位置获取、社交网络的实时消息推送等。

    传统的请求-响应模式的Web开发在处理此类业务场景时,通常采用实时通讯方案。比如常见的轮询方案,其原理简单易懂,就是客户端以一定的时间间隔频繁请求的方式向服务器发送请求,来保持客户端和服务器端的数据同步。其问题也很明显:当客户端以固定频率向服务器端发送请求时,服务器端的数据可能并没有更新,带来很多无谓请求,浪费带宽,效率低下。

    基于Flash,AdobeFlash通过自己的Socket实现完成数据交换,再利用Flash暴露出相应的接口给JavaScript调用,从而达到实时传输目的。此方式比轮询要高效,且因为Flash安装率高,应用场景广泛。然而,移动互联网终端上Flash的支持并不好:IOS系统中无法支持Flash,Android虽然支持Flash但实际的使用效果差强人意,且对移动设备的硬件配置要求较高。2012年Adobe官方宣布不再支持Android4.1+系统,宣告了Flash在移动终端上的死亡。

    传统的Web模式在处理高并发及实时性需求的时候,会遇到难以逾越的瓶颈,需要一种高效节能的双向通信机制来保证数据的实时传输。在此背景下,基于HTML5规范的、有Web
    TCP之称的
    WebSocket应运而生。早期HTML5并没有形成业界统一的规范,各个浏览器和应用服务器厂商有着各异的类似实现,如IBM的MQTT、Comet开源框架等。直到2014年,HTML5终于尘埃落地,正式落实为实际标准规范,各个应用服务器及浏览器厂商逐步开始统一,在
    JavaEE7中也实现了WebSocket协议。至此无论是客户端还是服务端的WebSocket都已完备。用户可以查阅HTML5规范,熟悉新的HTML协议规范及WebSocket支持。

    WebSocket 机制
    以下简要介绍一下WebSocket的原理及运行机制。

    WebSocket是HTML5下一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的。它与HTTP一样通过已建立的TCP连接来传输数据,但是它和HTTP最大不同是:
    WebSocket是一种双向通信协议。在建立连接后,WebSocket服务器端和客户端都能主动发送数据给对方或向对方接收数据,就像Socket一样;
    WebSocket需要像TCP一样,先建立连接,连接成功后才能相互通信。

    传统HTTP客户端与服务器请求响应模式如下图所示:
    在这里插入图片描述
    WebSocket模式客户端与服务器请求响应模式如下图:
    在这里插入图片描述

    上图对比可以看出,相对于传统HTTP每次请求-应答都需要客户端与服务端建立连接的模式,WebSocket是类似Socket的TCP长连接通讯模式。一旦WebSocket连接建立后,后续数据都以帧序列的形式传输。在客户端断开WebSocket连接或Server端中断连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实时性优势明显。

    相比HTTP长连接,WebSocket有以下特点:

    是真正的全双工方式,建立连接后客户端与服务器端是完全平等的,可以互相主动请求。而HTTP长连接基于HTTP,是传统的客户端对服务器发起请求的模式。

    HTTP长连接中,每次数据交换除了真正的数据部分外,服务器和客户端还要大量交换HTTP
    header,信息交换效率很低。Websocket协议通过第一个request建立了TCP连接之后,之后交换的数据都不需要发送 HTTP
    header就能交换数据,这显然和原有的HTTP协议有区别所以它需要对服务器和客户端都进行升级才能实现(主流浏览器都已支持HTML5)。此外还有
    multiplexing、不同的URL可以复用同一个WebSocket连接等功能。这些都是HTTP长连接不能做到的。

    下面再通过客户端和服务端交互的报文对比WebSocket通讯与传统HTTP的不同点:

    在客户端,new WebSocket实例化一个新的WebSocket客户端对象,请求类似 ws://yourdomain:port/path
    的服务端WebSocket
    URL,客户端WebSocket对象会自动解析并识别为WebSocket请求,并连接服务端端口,执行双方握手过程,客户端发送数据格式类似:

    GET /webfin/websocket/ HTTP/1.1
    Host: localhost
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
    Origin: http://localhost:8080
    Sec-WebSocket-Version: 13
    

    可以看到,客户端发起的WebSocket连接报文类似传统HTTP报文,Upgrade:websocket参数值表明这是WebSocket类型请求,Sec-WebSocket-Key是WebSocket客户端发送的一个
    base64编码的密文,要求服务端必须返回一个对应加密的Sec-WebSocket-Accept应答,否则客户端会抛出Error
    during WebSocket handshake错误,并关闭连接。

    服务端收到报文后返回的数据格式类似:

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
    

    Sec-WebSocket-Accept的值是服务端采用与客户端一致的密钥计算出来后返回客户端的,HTTP/1.1 101
    Switching
    Protocols表示服务端接受WebSocket协议的客户端连接,经过这样的请求-响应处理后,两端的WebSocket连接握手成功,
    后续就可以进行TCP通讯了。用户可以查阅WebSocket协议栈了解WebSocket客户端和服务端更详细的交互数据格式。

    在开发方面,WebSocket API 也十分简单:只需要实例化
    WebSocket,创建连接,然后服务端和客户端就可以相互发送和响应消息。在WebSocket 实现及案例分析部分可以看到详细的
    WebSocket API 及代码实现。

    腾讯云公网有日租类型七层负载均衡转发部分支持Websocket,目前包括英魂之刃、银汉游戏等多家企业已接入使用。当出现不兼容问题时,请修改websocket配置,websocket
    server不校验下图中圈出的字段:

    在这里插入图片描述
    一个使用WebSocket应用于视频的业务思路如下:

    • 使用心跳维护websocket链路,探测客户端端的网红/主播是否在线
    • 设置负载均衡7层的proxy_read_timeout默认为60s
    • 设置心跳为50s,即可长期保持Websocket不断开

    近期Websocket将开放自定义配置。

    展开全文
  • HTTP协议的瓶颈 影响HTTP网络请求的因素: 带宽 延迟 ...HTTP协议的瓶颈: ...WebSocket与HTTP ...WebSocket的握手: 服务器返回: AJAX轮询: 每隔一段时间就会重新发起请求去询问服务器,有...
  • WebSocket系列:爱奇艺号 WebSocket集群推送网关
  • WebSocket学习

    2020-06-01 21:13:53
    Http的瓶颈有: 一条连接上只可发送一个请求 请求只能从客户端开始。客户端不可以接收除响应以外的指令。 请求/响应首部未经压缩就发送。首部信息越多延迟越大。 发送冗长的首部。每次互相发送相
  • WebSocket基础

    千次阅读 2017-03-13 23:47:30
    什么是WebSocket WebSocket是Web客户端和服务端进行异步全双工通信的协议,可以用来创建高性能实时的Web应用。WebSocket通信协议于2011年被IETF定为标准RFC 6455,WebSocketAPI被W3C定为标准。
  • javascript可调用有W3C制定的The WebSocket Api内提供的WebSocket程序接口,实现WebSocket协议的全双工通信。例如:每30ms发生一次数据 let socket = new WebSocket( 'ws://www.abc.com/updates' ); socket....
  • WebSocket 实战

    2016-12-15 12:05:01
    WebSocket 实战 本文介绍了 HTML5 WebSocket 的由来,运作机制及客户端和服务端的 API 实现,重点介绍服务端(基于 Tomcat7)及客户端(基于浏览器原生 HTML5 API)实现的详细步骤;并通过实际客户案例描述了...
  • HTTP瓶颈以及解决方法之websocketHTTP的瓶颈就是:HTTP协议的性能受到限制,web页面加载时间过长,实时更新大量的数据无法妥善处理,但由于全球已经有很多的浏 览器都是基于HTTP协议,所以无法完全抛弃HTTP,因此...
  • websocket 协议

    2020-01-09 10:15:52
    WebSocket 协议和知识 WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。 WebSocket协议是基于TCP...
  • websocket基础

    2016-05-21 08:45:03
    赢家昨天来工作室,顺便聊到了即时多人在线游戏的服务器,之后又回忆起去年波波做的即时在线聊天,今天在看书的时候遇到了websocket这种技术.于是乎,入坑.
  • WebSocket详解

    千次阅读 2017-04-29 23:46:42
    WebSocket 前世今生 众所周知,Web 应用的交互过程通常是客户端通过浏览器发出一个请求,服务器端接收请求后进行处理并返回结果给客户端,客户端浏览器将信息呈现,这种机制对于信息变化不是特别频繁的应用尚可,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,765
精华内容 1,506
关键字:

websocket瓶颈