Changeset 321
- Timestamp:
- 06/30/08 17:52:04 (7 weeks ago)
- Location:
- branches
- Files:
-
- 9 modified
-
0.5/presentations/myspace/slides_outline2 (modified) (20 diffs)
-
kdev/daemon/orbited/static/BaseTCPConnection.js (modified) (4 diffs)
-
kdev/daemon/orbited/static/BaseTCPConnectionBuild.js (modified) (9 diffs)
-
kdev/daemon/orbited/static/BinaryTCPConnectionBuild.js (modified) (9 diffs)
-
kdev/daemon/orbited/static/JSONTCPConnectionBuild.js (modified) (9 diffs)
-
kdev/daemon/orbited/static/URL.js (modified) (1 diff)
-
kdev/daemon/orbited/static/transports/ServerSentEvents.js (modified) (3 diffs)
-
kdev/daemon/orbited/static/transports/transport.js (modified) (2 diffs)
-
kdev/daemon/orbited/tcp.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/0.5/presentations/myspace/slides_outline2
r268 r321 7 7 - countless architectures tested 8 8 - now we've found the best 9 - javascript work 9 10 - Lead architect of Kaazing's Enterprise Comet Server offering 10 11 - coming soon (to theatres everywhere...) … … 30 31 - Auctions 31 32 - Sports reporting 33 - Collaborative Editing 34 - Network monitor reporting / system administration 32 35 - Election Monitoring (Andrew Betts / London Paper) 33 - Collaborative Editing34 36 - Air traffic control (no joke) 35 - Network monitor reporting / system administration36 37 - 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 39 40 - Which brings us to Transports 40 41 … … 51 52 Slide: Iframe Diagram 52 53 53 - Parentpage has a callback "receive"54 - Application page has a callback "receive" 54 55 - Finishes loading, creates and iframe 55 56 - Iframe causes an HTTP request to the server … … 71 72 - Loading Bars 72 73 - Hour glasses 73 - clicking noises?! (wtf mate ^^)74 - clicking noises?! 74 75 75 76 Slide: Iframe Unacceptable 76 77 - Modern applications can't have clicking noises and hour glasses. 77 78 - The users would get too confused 78 - So Iframe streaming isn't th at popular79 - Instead, the winneris...79 - So Iframe streaming isn't the most popular transport 80 - Instead, the most popular transport is... 80 81 81 82 Slide: XHR Long polling … … 96 97 - still easy to implement 97 98 - and no usability issues! 99 - seems like a big win 98 100 - but how does long polling performance compare to iframe streaming? 99 101 - Consider an island off the coast … … 115 117 - It waits for the boat to come back 116 118 - It gets on, and waits for the boat to go to the island 119 - 3x travel duration 117 120 - Well Iframe streaming is the bridge, and the boat is long polling 118 121 - Meaning, long polling suffers from a 3x latency performance hit … … 120 123 Slide: Bandwidth comparison 121 124 - You also have to send headers all the time 122 - Your buddy says 'how 's it hanging'125 - Your buddy says 'hows it hanging' 123 126 - But the browser says 'GET /some/url HTTP/1.1\r\nUser-Agent: ...etc' 124 127 - 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! 126 129 - thats a 20x bandwidth increase in that case 127 130 … … 153 156 - transport for ff and safari 154 157 Slide: ready state 3 158 - don't do one event per request/response cycle 159 - do a hundred. a thousand... 155 160 - ready state 3 saves the day 156 161 - callbacks for download progress from server … … 178 183 179 184 - Then they went on to propose that the this be included in HTML5 180 - after discussions with other vendors, a new spec came up185 - after discussions with other vendors, gained support, a new spec came up 181 186 182 187 Slide: deprecated … … 186 191 - we can use the deprecated one in opera 8+ 187 192 188 Slide: Transport Conclusions 189 - You've seen the prettier side of Comet 193 Slide: Transport Conclusions 10.18.20 190 194 - Ten minutes to explain 191 195 - Years to discover … … 201 205 - That is to say, just imagine the most frustrating game you can 202 206 - That game is twice as fun as building transports 203 - But in the end204 207 205 208 Slide: sleek bridge 206 209 - We can avoid the boat transport (long polling) 207 210 - And provide great user experience 211 - get a nice looking bridge 208 212 209 213 Slide: sleek bridge image with orbited logo superimosed … … 220 224 - How do you put lots of users on one machine? 221 225 - Seems like such a hard problem, but really there's a simple trick 222 - And once you know the trick, its easy226 - And once you know the trick, its possible 223 227 - Don't use threads. 224 228 - People have tried this with servers like apache 225 - So areasonable thread count, of 20, will service 20 users229 - A reasonable thread count, of 20, will service 20 users 226 230 - A better user count is a 1000 though 227 231 - But a 1000 threads brings a system to its knees with context switches 228 232 - No comet, just thrashing 233 234 Slide: Comet + threads != scalable 229 235 - So use the little trick of omitting threads, and you're golden 230 236 - Build event-based servers 231 - You r comet apps won't haveto be like nature preserves237 - You don't want your comet apps to be like nature preserves 232 238 - You don't want your app to be a lonely desert with the occasional wanderer 233 239 - it should be a riot, with users tearing down the walls, sucking your resources dry, demanding more... … … 235 241 Slide: desert -> riot 236 242 - So use event based programming for your comet server 243 - And I guarantee, your app will be a riot, not a desert. 237 244 238 245 Slide: zzzz … … 241 248 242 249 Slide: Horizontal Scalability 250 - If one server supports 1000 users, does 2 support 2000? and n, n-1000? 243 251 - This is a truly tough problem 244 252 - Really though, it depends on the application 253 - No one answer. 245 254 - But a few core rules are in order 246 255 - 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 comet256 - 2. Only do Comet in the Comet server. no Pub/sub, no jabber/game server, no load balancing, just comet 248 257 - 3. Treat comet as the last leg of the journey 249 258 … … 252 261 - Developers like it, great. 253 262 - 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 wouldreal publish/subscribe message queues would be great263 - 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 256 265 - 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. 258 273 - So How do you integrate comet servers with X? 259 274 … … 279 294 - once for the bridge, once for the browser 280 295 - the bridge speaks xmpp to the jabber server, but json-chat (made up protocol) to the browser 296 - Clearly not the solution... 281 297 282 298 Slide: Victory march picture, maybe the planting of the american flag in some battle … … 286 302 287 303 Slide: 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 289 306 - It will 290 307 -traverse forward proxies … … 305 322 - and plain old tcp on the back 306 323 - 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. 309 326 - 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 311 330 312 331 Slide: Browser < - > ( comet Proxy + Jabber Diagram single machine) … … 316 335 317 336 Slide: Sigh of relief 318 - Because Comet isn't going to get in the way anymore319 - Scaling Comet applications isn't a twofold problem anymore337 - Because Comet isn't going to get in the way 338 - Scaling Comet applications horizontally isn't a twofold problem anymore 320 339 - If you know how to scale a network application, then you can scale a comet application. 321 340 322 341 Slide: Jabber server cloud with half Comet proxies, half normal 323 342 - And whats more, there's no difference between the browser and the desktop 324 - You get to325 343 326 344 … … 330 348 Slide: Jabber server with comet proxy on left, web app on the right, sql server behind both 331 349 - 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 332 355 - And your problems are over. 333 356 334 357 Slide:Conclusion (Bullseye (with orbited logo somewhere)) 335 - Transports are frustrating, but Orbited implements them (indeed, manyprojects take our implementation directly)358 - Transports are frustrating, but Orbited implements them (indeed, a number of projects take our implementation directly) 336 359 - Vertical Scalability and threads don't mix. Orbited use event-based network IO. 337 360 - 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 339 362 - TCPConnection is the perfect integration point. It works with all past, present, and future tcp/ip servers. Out of the box. 340 363 - Orbited provides that functionality today. -
branches/kdev/daemon/orbited/static/BaseTCPConnection.js
r221 r321 17 17 var pingTimer = null; 18 18 var numSendPackets = null; 19 19 var postId = 0; 20 20 self.connect = function(_url) { 21 console.log('url: ' + _url)22 21 if (self.readyState != -1 && self.readyState != 2) 23 22 throw new Error("connect may only be called on a closed socket"); 24 23 self.readyState = 0 25 var testUrl = new URL(_url);24 url = new URL(_url); 26 25 27 if (testUrl.isSameDomain(location.href)) { 28 alert('same domain'); 26 if (url.isSameDomain(location.href)) { 29 27 xhr = createXHR(); 30 28 } 31 29 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 36 32 if (path[path.length-1] != '/') 37 33 path += '/' 38 34 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) 41 36 } 42 37 else { 43 38 throw new Error("Invalid domain. BaseTCPConnection instances may only connect to same-domain or sub-domain hosts.") 44 39 } 45 url = testUrl.render() 46 attachTransport(); 40 getSession(); 47 41 } 48 49 42 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 } 50 71 var attachTransport = function() { 51 alert('attach transport')52 tcpUrl = url53 72 transport = new CometTransport() 54 73 transport.receivePayload = receivePayload; 55 transport.receiveTCPOpen = receiveTCPOpen;56 74 transport.receiveTCPClose = receiveTCPClose; 57 75 transport.receiveTCPPing = receiveTCPPing; 58 console.log('transport.connect: ' + tcpUrl)59 76 transport.connect(tcpUrl); 60 77 } … … 79 96 for (var i = 0; i < sendQueue.length; ++i) { 80 97 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" 82 99 } 83 100 // TODO: don't to this here. … … 120 137 var onTimeout = function() { 121 138 doClose(); 122 self.onclose(null);123 139 } 124 140 var resetPingTimer = function() { … … 135 151 } 136 152 var receiveTCPOpen = function(evt) { 137 // console.log('receiveTCPOpen');138 // console.log(evt.data);139 153 // TODO: use the EventListener interface if available (handleEvent) 140 154 lastEventId = evt.lastEventId; 141 155 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.qs146 oldUrl.path = newUrl.path147 tcpUrl = oldUrl.render()148 }149 */150 156 self.onopen(evt); 151 157 resetPingTimer(); 152 // window.setTimeout(tcp.onopen, 1000)153 // window.setTimeout("tcp.onopen()", 0)//function() { self.onopen(evt) }, 0)154 158 } 155 159 var receiveTCPClose = function(evt) { 156 160 // TODO: use the EventListener interface if available (handleEvent) 157 161 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(); 159 168 self.onclose(evt) 160 }161 var doClose = function() {162 self.readyState = 2163 transport.destroy();164 169 } 165 170 var receivePayload = function(evt) { -
branches/kdev/daemon/orbited/static/BaseTCPConnectionBuild.js
r219 r321 140 140 } 141 141 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 143 156 // end @include(URL.js) 144 157 … … 184 197 // connUrl.hash = "0" 185 198 url = connUrl.render() 186 console.log('addEventsource: ' + url)187 199 source.addEventSource(url) 188 200 document.body.appendChild(source) … … 276 288 var obj = createElement.call(this, name) 277 289 if (name == "event-source") { 278 alert('createElehttp://operawiki.info/OperaPerformancement')279 290 var SSEHandler = new FxSSE(obj); 280 291 } … … 359 370 } 360 371 xhr.onreadystatechange = function() { 361 console.log(xhr.readyState)362 372 switch (xhr.readyState) { 363 373 case 4: // disconnect case … … 399 409 } 400 410 } 401 console.log('setting timer and sending');402 411 operaTimer = setInterval(process, 50) 403 412 xhr.send(null); 404 413 } 405 414 var reconnect = function() { 406 console.log('reconnect!')407 415 clearInterval(operaTimer) 408 416 operaTimer = null; … … 528 536 529 537 self.connect = function(_url) { 530 console.log('url: ' + _url)531 538 if (self.readyState != -1 && self.readyState != 2) 532 539 throw new Error("connect may only be called on a closed socket"); 533 540 self.readyState = 0 534 var testUrl = new URL(_url);541 url = new URL(_url); 535 542 536 if (testUrl.isSameDomain(location.href)) { 537 alert('same domain'); 543 if (url.isSameDomain(location.href)) { 538 544 xhr = createXHR(); 539 545 } 540 546 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 545 549 if (path[path.length-1] != '/') 546 550 path += '/' 547 551 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) 550 553 } 551 554 else { 552 555 throw new Error("Invalid domain. BaseTCPConnection instances may only connect to same-domain or sub-domain hosts.") 553 556 } 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 } 559 587 var attachTransport = function() { 560 alert('attach transport')561 tcpUrl = url562 588 transport = new CometTransport() 563 589 transport.receivePayload = receivePayload; … … 565 591 transport.receiveTCPClose = receiveTCPClose; 566 592 transport.receiveTCPPing = receiveTCPPing; 567 console.log('transport.connect: ' + tcpUrl)568 593 transport.connect(tcpUrl); 569 594 } … … 629 654 var onTimeout = function() { 630 655 doClose(); 631 self.onclose(null);632 656 } 633 657 var resetPingTimer = function() { … … 644 668 } 645 669 var receiveTCPOpen = function(evt) { 646 // console.log('receiveTCPOpen');647 // console.log(evt.data);648 670 // TODO: use the EventListener interface if available (handleEvent) 649 671 lastEventId = evt.lastEventId; 650 672 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.qs655 oldUrl.path = newUrl.path656 tcpUrl = oldUrl.render()657 }658 673 self.onopen(evt); 659 674 resetPingTimer(); 660 // window.setTimeout(tcp.onopen, 1000)661 // window.setTimeout("tcp.onopen()", 0)//function() { self.onopen(evt) }, 0)662 675 } 663 676 var receiveTCPClose = function(evt) { 664 677 // TODO: use the EventListener interface if available (handleEvent) 665 678 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(); 667 685 self.onclose(evt) 668 }669 var doClose = function() {670 self.readyState = 2671 transport.destroy();672 686 } 673 687 var receivePayload = function(evt) { -
branches/kdev/daemon/orbited/static/BinaryTCPConnectionBuild.js
r219 r321 141 141 } 142 142 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 144 157 // end @include(URL.js) 145 158 … … 185 198 // connUrl.hash = "0" 186 199 url = connUrl.render() 187 console.log('addEventsource: ' + url)188 200 source.addEventSource(url) 189 201 document.body.appendChild(source) … … 276 288 var obj = createElement.call(this, name) 277 289 if (name == "event-source") { 278 alert('createElehttp://operawiki.info/OperaPerformancement')279 290 var SSEHandler = new FxSSE(obj); 280 291 } … … 359 370 } 360 371 xhr.onreadystatechange = function() { 361 console.log(xhr.readyState)362 372 switch (xhr.readyState) { 363 373 case 4: // disconnect case … … 399 409 } 400 410 } 401 console.log('setting timer and sending');