Changeset 321

Show
Ignore:
Timestamp:
06/30/08 17:52:04 (7 weeks ago)
Author:
heyadayo
Message:
 
Location:
branches
Files:
9 modified

Legend:

Unmodified
Added
Removed
  • branches/0.5/presentations/myspace/slides_outline2

    r268 r321  
    77    - countless architectures tested 
    88    - now we've found the best 
     9    - javascript work 
    910- Lead architect of Kaazing's Enterprise Comet Server offering 
    1011    - coming soon (to theatres everywhere...) 
     
    3031    - Auctions 
    3132    - Sports reporting 
     33    - Collaborative Editing 
     34    - Network monitor reporting / system administration 
    3235    - Election Monitoring (Andrew Betts / London Paper) 
    33     - Collaborative Editing 
    3436    - Air traffic control (no joke) 
    35     - Network monitor reporting / system administration 
    3637    - To name a few 
    37 - In practice though, everyone wants Comet without the need for flash 
    38 - Just plain old js and html 
     38- In practice though, everyone wants Comet without the need for flash or bad performance of polling 
     39- Just plain old js and html, low latency 
    3940- Which brings us to Transports 
    4041 
     
    5152Slide: Iframe Diagram 
    5253 
    53 - Parent page has a callback "receive" 
     54- Application page has a callback "receive" 
    5455- Finishes loading, creates and iframe 
    5556- Iframe causes an HTTP request to the server 
     
    7172- Loading Bars 
    7273- Hour glasses 
    73 - clicking noises?! (wtf mate ^^) 
     74- clicking noises?! 
    7475 
    7576Slide: Iframe Unacceptable 
    7677- Modern applications can't have clicking noises and hour glasses.  
    7778- The users would get too confused 
    78 - So Iframe streaming isn't that popular 
    79 - Instead, the winner is... 
     79- So Iframe streaming isn't the most popular transport 
     80- Instead, the most popular transport is... 
    8081 
    8182Slide: XHR Long polling 
     
    9697- still easy to implement 
    9798- and no usability issues! 
     99- seems like a big win 
    98100- but how does long polling performance compare to iframe streaming? 
    99101- Consider an island off the coast 
     
    115117- It waits for the boat to come back 
    116118- It gets on, and waits for the boat to go to the island 
     119- 3x travel duration 
    117120- Well Iframe streaming is the bridge, and the boat is long polling 
    118121- Meaning, long polling suffers from a 3x latency performance hit 
     
    120123Slide: Bandwidth comparison 
    121124- You also have to send headers all the time 
    122 - Your buddy says 'how's it hanging' 
     125- Your buddy says 'hows it hanging' 
    123126- But the browser says 'GET /some/url HTTP/1.1\r\nUser-Agent: ...etc' 
    124127- And the server says 'HTTP/1.1 200 ok\r\nContent-type....' 
    125 - your 15 byte message can easily incur 300 bytes of headers 
     128- your 15 byte message can easily incur 300 bytes of headers, or more! 
    126129- thats a 20x bandwidth increase in that case 
    127130 
     
    153156- transport for ff and safari 
    154157Slide: ready state 3 
     158- don't do one event per request/response cycle 
     159- do a hundred. a thousand...  
    155160- ready state 3 saves the day 
    156161- callbacks for download progress from server 
     
    178183 
    179184- Then they went on to propose that the this be included in HTML5 
    180 - after discussions with other vendors, a new spec came up 
     185- after discussions with other vendors, gained support, a new spec came up 
    181186 
    182187Slide: deprecated 
     
    186191- we can use the deprecated one in opera 8+ 
    187192 
    188 Slide: Transport Conclusions 
    189 - You've seen the prettier side of Comet 
     193Slide: Transport Conclusions 10.18.20 
    190194- Ten minutes to explain  
    191195- Years to discover 
     
    201205- That is to say, just imagine the most frustrating game you can 
    202206- That game is twice as fun as building transports 
    203 - But in the end 
    204207 
    205208Slide: sleek bridge 
    206209- We can avoid the boat transport (long polling) 
    207210- And provide great user experience 
     211- get a nice looking bridge 
    208212 
    209213Slide: sleek bridge image with orbited logo superimosed 
     
    220224- How do you put lots of users on one machine? 
    221225- Seems like such a hard problem, but really there's a simple trick 
    222 - And once you know the trick, its easy 
     226- And once you know the trick, its possible 
    223227- Don't use threads. 
    224228- People  have tried this with servers like apache 
    225 - So a reasonable thread count, of 20, will service 20 users 
     229- A reasonable thread count, of 20, will service 20 users 
    226230- A better user count is a 1000 though 
    227231- But a 1000 threads brings a system to its knees with context switches 
    228232- No comet, just thrashing 
     233 
     234Slide: Comet + threads != scalable 
    229235- So use the little trick of omitting threads, and you're golden 
    230236- Build event-based servers 
    231 - Your comet apps won't have to be like nature preserves 
     237- You don't want your comet apps to be like nature preserves 
    232238- You don't want your app to be a lonely desert with the occasional wanderer 
    233239- it should be a riot, with users tearing down the walls, sucking your resources dry, demanding more... 
     
    235241Slide: desert -> riot 
    236242- So use event based programming for your comet server 
     243- And I guarantee, your app will be a riot, not a desert.  
    237244 
    238245Slide: zzzz 
     
    241248 
    242249Slide: Horizontal Scalability 
     250- If one server supports 1000 users, does 2 support 2000? and n, n-1000? 
    243251- This is a truly tough problem 
    244252- Really though, it depends on the application 
     253- No one answer. 
    245254- But a few core rules are in order 
    246255- 1. Don't share state between comet servers 
    247 - 2. Only do Comet in the Comet server. no Pub/sub, no jabber/game server, just comet 
     256- 2. Only do Comet in the Comet server. no Pub/sub, no jabber/game server, no load balancing, just comet 
    248257- 3. Treat comet as the last leg of the journey 
    249258 
     
    252261- Developers like it, great. 
    253262- But it was already a hard problem before Browser's existed 
    254 - And the people solving the problem, RabbitMQ/ActiveMQ, aren't part of the comet community. 
    255 - Integrating comet would real publish/subscribe message queues would be great 
     263- And the people solving the problem, RabbitMQ/ActiveMQ, aren't part of the comet community. (there have  been minor inroads) 
     264- Integrating streaming comet sith real publish/subscribe message queues would be great 
    256265- But, thats just a specific case of a larger issue 
    257 - And really, integrating comet with existing technologies would allow us to solve the horizontal scaling problem however these existing technologies already solve it. 
     266- The real issue with scaling comet applications is that  
     267     - Comet is difficult 
     268     - Comet imposes architectural constraints on web apploications that we aren't used to (can't do round robin balancing per http request) 
     269     - Its a moving part that has to be closely tied to the other pieces of the system 
     270- But integrating comet with existing technologies would allow us to solve the horizontal scaling problem however these existing technologies already solve it. 
     271- How could you scale a thick client deployment? 
     272- We want that to be the only question to answer when scaling a comet application. 
    258273- So How do you integrate comet servers with X? 
    259274 
     
    279294- once for the bridge, once for the browser 
    280295- the bridge speaks xmpp to the jabber server, but json-chat (made up protocol) to the browser 
     296- Clearly not the solution... 
    281297 
    282298Slide: Victory march picture, maybe the planting of the american flag in some battle 
     
    286302 
    287303Slide: TCPConnection (word) 
    288 - I've been working closely with whatwg/w3c to specify a protocol and api that solves all of our problems 
     304- I've been working closely with whatwg/w3c to specify the protocol and api that solves all of our problems 
     305- tcpconnection is just like a socket, but for javsacript in browsers 
    289306- It will  
    290307    -traverse forward proxies 
     
    305322- and plain old tcp on the back 
    306323- So you put it in front of ANY tcp server 
    307 - and the browsers can interact as if they'd connected directly to the server over tcp. 
    308 - and the server doesn't need to be altered at all. 
     324- and the browsers can interact as if they'd connected directly to the backend server over tcp. 
     325- and the server doesn't need to be altered whatsoever. 
    309326- No need for a bridge or dispatch protocol 
    310 - but we can simplify this picture still 
     327- Much less complex means easier to scale 
     328- Load Balancing? 
     329- We can simplify this picture still 
    311330 
    312331Slide: Browser < - > ( comet Proxy + Jabber Diagram single machine) 
     
    316335 
    317336Slide: Sigh of relief 
    318 - Because Comet isn't going to get in the way anymore 
    319 - Scaling Comet applications isn't a twofold problem anymore 
     337- Because Comet isn't going to get in the way 
     338- Scaling Comet applications horizontally isn't a twofold problem anymore 
    320339- If you know how to scale a network application, then you can scale a comet application. 
    321340 
    322341Slide: Jabber server cloud with half Comet proxies, half normal 
    323342- And whats more, there's no difference between the browser and the desktop 
    324 - You get to  
    325343 
    326344 
     
    330348Slide: Jabber server with comet proxy on left, web app on the right, sql server behind both 
    331349- Just have the network server and the web app coordinate on the back end 
     350- put the sql server behind both 
     351- User creates an account over the web app 
     352- but can log in to jabber 
     353- jabber saves logs to the database 
     354- and the user can see those logs via the web app 
    332355- And your problems are over. 
    333356 
    334357Slide:Conclusion  (Bullseye (with orbited logo somewhere)) 
    335 - Transports are frustrating, but Orbited implements them (indeed, many projects take our implementation directly) 
     358- Transports are frustrating, but Orbited implements them (indeed, a number of projects take our implementation directly) 
    336359- Vertical Scalability and threads don't mix. Orbited use event-based network IO. 
    337360- Horizontal scalability is tough because you have two problems. 
    338 - If you can solve integration, then you can get a handle on horizontal scalability 
     361- If you can solve integration, then you can get a handle on horizontal scalability by normal means 
    339362- TCPConnection is the perfect integration point. It works with all past, present, and future tcp/ip servers. Out of the box. 
    340363- Orbited provides that functionality today. 
  • branches/kdev/daemon/orbited/static/BaseTCPConnection.js

    r221 r321  
    1717    var pingTimer = null; 
    1818    var numSendPackets = null; 
    19  
     19    var postId = 0; 
    2020    self.connect = function(_url) { 
    21         console.log('url: ' + _url) 
    2221        if (self.readyState != -1 && self.readyState != 2) 
    2322            throw new Error("connect may only be called on a closed socket"); 
    2423        self.readyState = 0 
    25         var testUrl = new URL(_url); 
     24        url = new URL(_url); 
    2625         
    27         if (testUrl.isSameDomain(location.href)) { 
    28             alert('same domain'); 
     26        if (url.isSameDomain(location.href)) { 
    2927            xhr = createXHR(); 
    3028        } 
    3129 
    32         else if (testUrl.isSameParentDomain(location.href)) { 
    33 //            alert('using XSubdomainRequest') 
    34 //            document.domain = document.domain 
    35             var path = testUrl.path 
     30        else if (url.isSameParentDomain(location.href)) { 
     31            var path = url.path 
    3632            if (path[path.length-1] != '/') 
    3733                path += '/' 
    3834            path += 'static/XSubdomainBridge.html' 
    39             console.log('xdr path: ' + path) 
    40             xhr = new XSubdomainRequest(testUrl.domain, testUrl.port, path) 
     35            xhr = new XSubdomainRequest(url.domain, url.port, path) 
    4136        } 
    4237        else { 
    4338            throw new Error("Invalid domain. BaseTCPConnection instances may only connect to same-domain or sub-domain hosts.") 
    4439        } 
    45         url = testUrl.render() 
    46         attachTransport(); 
     40        getSession(); 
    4741    } 
    48      
    4942 
     43   var getSession = function() { 
     44       xhr.open('POST', url.render(), true); 
     45       xhr.onreadystatechange = function() { 
     46            switch(xhr.readyState) { 
     47                case 4: 
     48                    switch(xhr.status) { 
     49                        case 201: 
     50                            var newUrl = new URL(xhr.getResponseHeader('Location')) 
     51                            tcpUrl = newUrl.render() 
     52                            receiveTCPOpen(); 
     53                            attachTransport(); 
     54                            break; 
     55                        // 200 "redirect" is Untested 
     56                        case 200: 
     57                            var newUrl = new URL(xhr.getResponseHeader('Location')) 
     58                            var curUrl = new URL(url) 
     59                            curUrl.merge(newUrl) 
     60                            tcpUrl = curUrl.render() 
     61                            getSession(); 
     62                            break; 
     63                        default: 
     64                            doClose(); 
     65                            break; 
     66                    } 
     67            } 
     68        } 
     69        xhr.send(null) 
     70    } 
    5071    var attachTransport = function() { 
    51         alert('attach transport') 
    52         tcpUrl = url 
    5372        transport = new CometTransport() 
    5473        transport.receivePayload = receivePayload; 
    55         transport.receiveTCPOpen = receiveTCPOpen; 
    5674        transport.receiveTCPClose = receiveTCPClose; 
    5775        transport.receiveTCPPing = receiveTCPPing; 
    58         console.log('transport.connect: ' + tcpUrl) 
    5976        transport.connect(tcpUrl); 
    6077    } 
     
    7996        for (var i = 0; i < sendQueue.length; ++i) { 
    8097            var data = sendQueue[i] 
    81             payload += "data:" + data.split("\n").join("\r\ndata:") + "\r\n\r\n" 
     98            payload += "data:" + data.split("\n").join("\r\ndata:") + "\r\n" + "id: " + (++postId).toString() + "\r\n\r\n" 
    8299        } 
    83100        // TODO: don't to this here. 
     
    120137    var onTimeout = function() { 
    121138        doClose(); 
    122         self.onclose(null); 
    123139    } 
    124140    var resetPingTimer = function() { 
     
    135151    } 
    136152    var receiveTCPOpen = function(evt) { 
    137 //        console.log('receiveTCPOpen'); 
    138 //        console.log(evt.data); 
    139153        // TODO: use the EventListener interface if available (handleEvent) 
    140154        lastEventId = evt.lastEventId; 
    141155        self.readyState = 1 
    142 /*        if (evt.data != null && evt.data.length > 0) { 
    143             var newUrl = new URL(evt.data); 
    144             var oldUrl = new URL(tcpUrl); 
    145             oldUrl.qs = newUrl.qs 
    146             oldUrl.path = newUrl.path 
    147             tcpUrl = oldUrl.render() 
    148         } 
    149 */ 
    150156        self.onopen(evt); 
    151157        resetPingTimer(); 
    152 //        window.setTimeout(tcp.onopen, 1000) 
    153 //        window.setTimeout("tcp.onopen()", 0)//function() { self.onopen(evt) }, 0) 
    154158    } 
    155159    var receiveTCPClose = function(evt) { 
    156160        // TODO: use the EventListener interface if available (handleEvent) 
    157161        lastEventId = evt.lastEventId; 
    158         doClose(); 
     162        doClose(evt); 
     163    } 
     164    var doClose = function(evt) { 
     165        self.readyState = 2 
     166        if (transport != null) 
     167            transport.destroy(); 
    159168        self.onclose(evt) 
    160     } 
    161     var doClose = function() { 
    162         self.readyState = 2 
    163         transport.destroy(); 
    164169    } 
    165170    var receivePayload = function(evt) { 
  • branches/kdev/daemon/orbited/static/BaseTCPConnectionBuild.js

    r219 r321  
    140140    } 
    141141 
    142 } 
     142    self.merge = function(targetUrl) { 
     143        if (typeof(self.protocol) != "undefined" && self.protocol.length > 0) { 
     144            self.protocol = targetUrl.protocol 
     145        } 
     146        if (targetUrl.domain.length > 0) { 
     147            self.domain = targetUrl.domain 
     148            self.port = targetUrl.port 
     149        } 
     150        self.path = targetUrl.path 
     151        self.qs = targetUrl.qs 
     152        self.hash = targetUrl.hash 
     153    } 
     154} 
     155 
    143156// end @include(URL.js) 
    144157 
     
    184197//                connUrl.hash = "0" 
    185198                url = connUrl.render() 
    186                 console.log('addEventsource: ' + url) 
    187199                source.addEventSource(url) 
    188200                document.body.appendChild(source) 
     
    276288        var obj = createElement.call(this, name) 
    277289        if (name == "event-source") { 
    278             alert('createElehttp://operawiki.info/OperaPerformancement') 
    279290            var SSEHandler = new FxSSE(obj); 
    280291        } 
     
    359370        } 
    360371        xhr.onreadystatechange = function() { 
    361             console.log(xhr.readyState) 
    362372            switch (xhr.readyState) { 
    363373                case 4: // disconnect case 
     
    399409            } 
    400410        } 
    401         console.log('setting timer and sending'); 
    402411        operaTimer = setInterval(process, 50) 
    403412        xhr.send(null); 
    404413    } 
    405414    var reconnect = function() { 
    406         console.log('reconnect!') 
    407415        clearInterval(operaTimer) 
    408416        operaTimer = null; 
     
    528536 
    529537    self.connect = function(_url) { 
    530         console.log('url: ' + _url) 
    531538        if (self.readyState != -1 && self.readyState != 2) 
    532539            throw new Error("connect may only be called on a closed socket"); 
    533540        self.readyState = 0 
    534         var testUrl = new URL(_url); 
     541        url = new URL(_url); 
    535542         
    536         if (testUrl.isSameDomain(location.href)) { 
    537             alert('same domain'); 
     543        if (url.isSameDomain(location.href)) { 
    538544            xhr = createXHR(); 
    539545        } 
    540546 
    541         else if (testUrl.isSameParentDomain(location.href)) { 
    542 //            alert('using XSubdomainRequest') 
    543 //            document.domain = document.domain 
    544             var path = testUrl.path 
     547        else if (url.isSameParentDomain(location.href)) { 
     548            var path = url.path 
    545549            if (path[path.length-1] != '/') 
    546550                path += '/' 
    547551            path += 'static/XSubdomainBridge.html' 
    548             console.log('xdr path: ' + path) 
    549             xhr = new XSubdomainRequest(testUrl.domain, testUrl.port, path) 
     552            xhr = new XSubdomainRequest(url.domain, url.port, path) 
    550553        } 
    551554        else { 
    552555            throw new Error("Invalid domain. BaseTCPConnection instances may only connect to same-domain or sub-domain hosts.") 
    553556        } 
    554         url = testUrl.render() 
    555         attachTransport(); 
    556     } 
    557      
    558  
     557        getSession(); 
     558    } 
     559 
     560   var getSession = function() { 
     561       xhr.open('POST', url.render(), true); 
     562       xhr.onreadystatechange = function() { 
     563            switch(xhr.readyState) { 
     564                case 4: 
     565                    switch(xhr.status) { 
     566                        case 201: 
     567                            var newUrl = new URL(xhr.getResponseHeader('Location')) 
     568                            tcpUrl = newUrl.render() 
     569                            attachTransport(); 
     570                            break; 
     571                        // 200 "redirect" is Untested 
     572                        case 200: 
     573                            var newUrl = new URL(xhr.getResponseHeader('Location')) 
     574                            var curUrl = new URL(url) 
     575                            curUrl.merge(newUrl) 
     576                            tcpUrl = curUrl.render() 
     577                            getSession(); 
     578                            break; 
     579                        default: 
     580                            doClose(); 
     581                            break; 
     582                    } 
     583            } 
     584        } 
     585        xhr.send(null) 
     586    } 
    559587    var attachTransport = function() { 
    560         alert('attach transport') 
    561         tcpUrl = url 
    562588        transport = new CometTransport() 
    563589        transport.receivePayload = receivePayload; 
     
    565591        transport.receiveTCPClose = receiveTCPClose; 
    566592        transport.receiveTCPPing = receiveTCPPing; 
    567         console.log('transport.connect: ' + tcpUrl) 
    568593        transport.connect(tcpUrl); 
    569594    } 
     
    629654    var onTimeout = function() { 
    630655        doClose(); 
    631         self.onclose(null); 
    632656    } 
    633657    var resetPingTimer = function() { 
     
    644668    } 
    645669    var receiveTCPOpen = function(evt) { 
    646 //        console.log('receiveTCPOpen'); 
    647 //        console.log(evt.data); 
    648670        // TODO: use the EventListener interface if available (handleEvent) 
    649671        lastEventId = evt.lastEventId; 
    650672        self.readyState = 1 
    651         if (evt.data != null && evt.data.length > 0) { 
    652             var newUrl = new URL(evt.data); 
    653             var oldUrl = new URL(tcpUrl); 
    654             oldUrl.qs = newUrl.qs 
    655             oldUrl.path = newUrl.path 
    656             tcpUrl = oldUrl.render() 
    657         } 
    658673        self.onopen(evt); 
    659674        resetPingTimer(); 
    660 //        window.setTimeout(tcp.onopen, 1000) 
    661 //        window.setTimeout("tcp.onopen()", 0)//function() { self.onopen(evt) }, 0) 
    662675    } 
    663676    var receiveTCPClose = function(evt) { 
    664677        // TODO: use the EventListener interface if available (handleEvent) 
    665678        lastEventId = evt.lastEventId; 
    666         doClose(); 
     679        doClose(evt); 
     680    } 
     681    var doClose = function(evt) { 
     682        self.readyState = 2 
     683        if (transport != null) 
     684            transport.destroy(); 
    667685        self.onclose(evt) 
    668     } 
    669     var doClose = function() { 
    670         self.readyState = 2 
    671         transport.destroy(); 
    672686    } 
    673687    var receivePayload = function(evt) { 
  • branches/kdev/daemon/orbited/static/BinaryTCPConnectionBuild.js

    r219 r321  
    141141    } 
    142142 
    143 } 
     143    self.merge = function(targetUrl) { 
     144        if (typeof(self.protocol) != "undefined" && self.protocol.length > 0) { 
     145            self.protocol = targetUrl.protocol 
     146        } 
     147        if (targetUrl.domain.length > 0) { 
     148            self.domain = targetUrl.domain 
     149            self.port = targetUrl.port 
     150        } 
     151        self.path = targetUrl.path 
     152        self.qs = targetUrl.qs 
     153        self.hash = targetUrl.hash 
     154    } 
     155} 
     156 
    144157// end @include(URL.js) 
    145158 
     
    185198//                connUrl.hash = "0" 
    186199                url = connUrl.render() 
    187                 console.log('addEventsource: ' + url) 
    188200                source.addEventSource(url) 
    189201                document.body.appendChild(source) 
     
    276288        var obj = createElement.call(this, name) 
    277289        if (name == "event-source") { 
    278             alert('createElehttp://operawiki.info/OperaPerformancement') 
    279290            var SSEHandler = new FxSSE(obj); 
    280291        } 
     
    359370        } 
    360371        xhr.onreadystatechange = function() { 
    361             console.log(xhr.readyState) 
    362372            switch (xhr.readyState) { 
    363373                case 4: // disconnect case 
     
    399409            } 
    400410        } 
    401         console.log('setting timer and sending');