Ember at Scale
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 37 | |
Author | ||
License | CC Attribution - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/34696 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
EmberConf 201629 / 37
4
5
7
10
11
13
14
15
16
17
20
23
24
25
26
27
29
30
31
32
00:00
VideoconferencingCodeScale (map)MassCartesian coordinate systemSelf-organizationProfessional network serviceNumberSoftware frameworkEnumerated typeMultiplication signScaling (geometry)XMLComputer animation
00:48
Linker (computing)Chemical equationProduct (business)SoftwareKolmogorov complexityReduction of orderCorrelation and dependenceMathematicsLogical constantCartesian coordinate systemSoftware frameworkBlogNumberMathematics10 (number)Type theory1 (number)Product (business)Moving averageSelf-organizationUser interfaceSoftwareBenchmarkGroup actionVirtualizationRhombusLibrary (computing)Coma BerenicesKey (cryptography)Query languagePhysical systemWave packetProper mapData managementFreewareProcess (computing)Replication (computing)TrailPoint (geometry)Event horizonGoodness of fitObject (grammar)Stack (abstract data type)Web pageNamespaceSpacetimeProjective planeRevision controlCASE <Informatik>Client (computing)System callLevel (video gaming)Chemical equationVideo gameStability theoryMultiplication signLine (geometry)AnalogyShared memorySoftware developerLink (knot theory)Online helpData structurePresentation of a groupDatabaseWeb-DesignerRight anglePropagatorScaling (geometry)Set (mathematics)Staff (military)BitBuildingSimilarity (geometry)Computer animation
10:32
VolumenvisualisierungWeb pageComputer networkBoundary value problemCodierung <Programmierung>Server (computing)Compilation albumWeb browserInstallation artMaxima and minimaMobile appBootingBitStreaming mediaWeb browserLibrary (computing)Proxy serverCartesian coordinate systemClient (computing)Server (computing)Asynchronous Transfer ModeInformationMultiplication signBootingPhase transitionReplication (computing)Normal (geometry)Term (mathematics)SoftwareProduct (business)Pattern languageProof theoryComplete metric space2 (number)Dependent and independent variablesType theorySubject indexingRoundness (object)Endliche ModelltheorieBuildingSystem callCodeACIDDifferent (Kate Ryan album)Connected spaceProfil (magazine)TouchscreenPhysical systemService (economics)Scripting languageGreatest elementSerial portBlock (periodic table)Process (computing)NumberState of matterNetwork topologyForcing (mathematics)DiagramComputer architectureLevel (video gaming)String (computer science)Revision controlCoefficient of determinationPoint (geometry)Disk read-and-write headVolumenvisualisierungCASE <Informatik>Reading (process)Mathematical analysisMobile appPower (physics)Data centerFacebookVisualization (computer graphics)CodeWeb pageLatent heatMereologySemiconductor memoryData storage deviceCommon Language InfrastructureCodierung <Programmierung>Network socketWeb 2.0ChainHookingRoutingAreaArtistic renderingResolvent formalism
20:15
Mobile appComputer wormRandom numberProcess (computing)Linker (computing)Subject indexingTwitterMereologyMobile appScalabilityType theoryMobile WebArtistic renderingJava appletBenchmarkLibrary (computing)Set (mathematics)SoftwareGeneric programmingVideo gameProxy serverProcess (computing)Message passingStreaming mediaData managementCartesian coordinate systemTelecommunicationVolumenvisualisierungQueue (abstract data type)Client (computing)Level (video gaming)Scripting languageBitCommon Language InfrastructureDisk read-and-write headInstance (computer science)Slide rulePhysical systemNormal (geometry)BuildingFormal languageContent delivery networkShared memoryServer (computing)Software developerGraphical user interfaceAreaAssociative propertyMetric systemLoginRoutingGame controllerMultiplication signComputer architectureBootingWeb pageInterprozesskommunikationNumberFlagCore dumpDirection (geometry)Profil (magazine)Android (robot)Goodness of fitWritingStandard deviationCodeReplication (computing)Cycle (graph theory)DiagramService (economics)SpacetimeQuicksortLink (knot theory)Power (physics)First-person shooterSystem callQuantumDigital electronicsBefehlsprozessorFunctional (mathematics)Online helpFile formatCode division multiple accessAdditionExecution unitConnectivity (graph theory)Web browserDifferent (Kate Ryan album)Computer animation
Transcript: English(auto-generated)
00:12
All right, so I'm here to talk about Ember. But I'd first like to invite you all to join me on my professional network, which is LinkedIn.
00:24
But yeah, I'm actually here to talk about Ember. So Ember has been really successful at allowing small teams to build high-quality applications in a relatively short amount of time. But what would it look like if you took that same framework that allows these small teams to be extremely productive, and you unleash it on a massive engineering organization?
00:45
So the name of my talk is Ember at Scale. As Luke mentioned, my name is Chad Hightela. I'm a staff engineer at LinkedIn, where I work on a team called Presentation Infrastructure. And we're primarily focused with building client-side solutions to help product teams build products.
01:04
And so this is our story about picking Ember, the things that we considered, and some of the problems that we solved along the way. But first, before I get into using Ember at LinkedIn, we first need to understand where LinkedIn came from.
01:21
And to do so, we have to at least go back to when I joined the company. So I joined the company in 2013. It's almost three years to the day, actually. And at that time, LinkedIn had about 3,600 employees. And we had about 275 million members.
01:41
So at this point, we're still not like a small company. We're actually pretty large. But for anybody who's familiar with LinkedIn knows that it's a much bigger company than 3,600 employees today, and we have 400 million members. And so one of the lessons that I quickly learned when I was at LinkedIn,
02:01
I had come from a startup, was that any company of this size needs to have a very good product and technology balance. So as I mentioned, this was new to me because I literally rode the JavaScript hype train of 2011 and was able to ship a backbone Angular
02:20
and Ember application into production at the startup. And so I mention this because the first project that I worked on was use JSPs, and I had never used JSPs up until this point in my career. But not only was I using JSPs, I was actually working on a 12-year-old system
02:41
that talked to an Oracle backend, and this was actually the original tech stack that was built when all the co-founders were in Reid Hoffman's living room getting the first version of LinkedIn out the door. So me coming to LinkedIn, I'm like, what year is this?
03:00
I came from this place where I was doing a lot of things with JavaScript, and I was really surprised by, you know, that I was building something in JSPs. And so there's this quote, if it ain't broke, don't fix it. Clearly this is by somebody that is not in the JavaScript community because we tend to reinvent the wheel
03:23
about every six months or so. But when you start thinking about this rationally, it makes sense. When you're getting tens of millions of users to sign up year over year, the technology is not the problem. And you only really need to reassess the technology
03:41
when it's hindering your ability to create new products and being able to iterate on existing ones. So 2014 rolls around, and just in this one year, we went from 3,500 employees to 6,000 employees, so almost doubled.
04:00
And we also added about 60 million users during that first year that I was there. So lots of people, both on the employee side and on the user side, or member side. But it came pretty clear to us that it was becoming harder and harder for us to iterate.
04:21
We had a lot of software rot. And so if you looked at any given page on LinkedIn.com, you would see that there was YUI, jQuery, Backbone, Dust, JSPs, and then a bunch of internal libraries that were used to kind of cobble together a user interface.
04:40
Not only that, we didn't have a proper dependency management system. So what it really meant was, when you're creating a new product, was we had this method called li.namespace, and what it allowed you to do was register a namespace into a global object. And that's basically where you wrote your product. So in 2014, I joined a team to help reduce this complexity
05:06
and unify the text stacks that we were using to build user interfaces. And so, like any other serious company out there, what you end up doing is getting some type of design and then building that design in n number of frameworks,
05:22
just to kind of get a feel of how the framework works, what problems does it solve for me, and how does it actually attack the problems. But HorseJS kind of like puts it more elegantly. It's always Ember versus somebody. But I think this is more towards the benchmarking blogs
05:42
that you'll see about, hey, let's take the virtual DOM and benchmark it against Ember. And we kind of saw some of this earlier this morning of comparing and contrasting frameworks. And benchmarks are really good, and it's important to be benchmarking the application or the framework that you're gonna pick,
06:02
but it can't be the only thing that you consider. So at LinkedIn, we have to really consider about how the organization really thinks about technology and how they think about building product. And one of those things that comes to mind
06:23
right off the bat is all the technology that we use at LinkedIn that's used across many different products there is centrally supported by a team. It isn't a single team because you have various concerns so there's a team that works on the REST framework, there's a team that works on databases and data pipelines,
06:43
and there's people like me that work on clients. But the idea is that if you're going to build an application, you have a set of tools to build from. And so having the shared infrastructure solves about 90% of the problems that developers would have
07:01
if they were to start with nothing. And all they're really responsible for is building the product on top of these shared solutions. There's actually a really great talk by Steve Jobs from like 1997 that is talking about pitching cocoa and how it solves a lot of these common problems that no developers actually want to think about
07:20
and all they want to do is build their product. And the analogy is basically that cocoa is a scaffolding for applications and it starts you off on floor 26 instead of floor nine when you're going out to build your product. And we most definitely have a similar goal at LinkedIn
07:41
is we want to share as much infrastructure as possible. And so because we're doing shared infrastructure, less is actually more for us and the reason for that is like we really like to holistically solve problems. To give you an example of this, internally, tracking across all of the applications
08:01
has to be done in a very specced out way. There's a schema for all tracking events. And when you scale, you want to make this as dead simple as possible for developers to comply with tracking at this scale. And so what we did internally was we built an Ember add-on
08:22
for tracking events and once you install it, you're 90% of the way there to being compliant for tracking. You just basically have to instrument your application with the event names of where you're going to do tracking but things like actions happen for free. You just need to supply it with the tracking key that you're doing.
08:43
And then the other thing that we really had to take in consideration is that the only change or the only constant is change and the side is a little bit backwards but you get the idea. And so there's multiple levels to this and this is true about many things in software and in life but the thing that we really concentrated on
09:02
was that we allow people to move around from team to team in the organization and it's really great for people's careers because you get to work on very interesting problems or the problems that you're most interested in but it does come at a cost when you don't have shared solutions to problems. And this was very much the case when for the client side stuff.
09:22
I'd worked on three teams in the first year and a half that I was at LinkedIn trying to figure out what I wanted to do and this was clearly a problem. And the other thing is that JavaScript community is kind of crazy and web development in general is crazy as I alluded to before that things change quite often.
09:44
And so we wanted something that evolved over time but made certain guarantees about stability in the API when releases were going to actually happen. And so we ended up picking Ember and we think that Ember aligns how LinkedIn thinks about building products
10:01
and how we think about managing technology. And so Ember allows you to scale because you have shared solutions and conventions to solve common problems. So Ember provides you with enough scaffolding that starts you off on floor 23 instead of floor six
10:24
but you're probably gonna still need to solve some pretty interesting problems at the infrastructure layer. And so now I kind of want to talk about those interesting problems that we faced and how we attack them in the hopes that we can take these ideas and instill them into the community and maybe build floors 24 and 25
10:42
so that we as a community can have shared solutions to these problems. So Tom and Yehuda talked a little bit this morning about initial render performance and this was something that we thought quite a bit about before we even started building
11:00
our Ember application at LinkedIn. We feel like we should be able to leverage the server to help solve some of the problems in initial render. So I'm gonna walk through on how we did that. So we created this piece of infrastructure called the base page renderer and it's otherwise known as the BPR, not PBR
11:21
but you get the idea. And it's responsible for serving the index.html of an Ember app. But not only is it responsible for serving the index.html, we look at the base page renderer as a performance enhancement on top of client-side applications.
11:41
And the reason why we look at it as an enhancement on top of client-side applications is that the BPR can run in three different types of modes. It runs in vanilla mode which is probably the mode that most people are familiar with. It's like how you would normally build an Ember application where you have an index.html come down
12:01
from either the server or some CDN. Inside of that index.html you have some script tags. The script tags will go out to the CDN again. You'll get some assets back. Once those assets come back, they parse eval. You start booting your application up. You then go back to the server to fetch some data. And then finally you come back to your application
12:21
and you go render the screen. So that's the vanilla mode. And then there's server-side rendering which I'm not gonna go too much into because Tom kind of basically talked about fast boot this morning. But we do have the ability to run the BPR in SSR mode as well.
12:41
And the last mode that we can run the base page renderer in is this mode called BigPipe. And I wanna spend a little bit of time to talk about BigPipe because I think this is an idea that not a lot of people are talking about in ways that we can leverage some of the infrastructure that's been built for fast boot.
13:01
So the term BigPipe was actually coined by Facebook in 2010. So at this year this idea is like six years old. But we need to get creative on how we're going to build these applications in the future and I think this is a good way of doing it. But anyways, what BigPipe actually means is that you're just going to keep
13:21
the HTTP connection alive and you're gonna chunk encode the HTML that you're sending down to the browser. And so this is actually part of the HTTP 1.1 specification it's been in browsers for a very long time. And so to give some visualization
13:41
of what chunked encoding does for you is when you do server processing for like let's say a normal website, there's two ways that you can think about rendering or sending out the index.html. You can do what is known as store and forward where you're just building up the document in memory and then once the document is complete
14:01
you send the fully materialized document down to the browser. The other one is chunked encoding which is if you are processing, every time you're processing a chunk you're actually streaming it down to the browser once it's ready. So this gives you the ability of like this concept of a stream
14:21
and you're streaming down HTML to the browser. And so this isn't like a web socket or anything like this this is HTTP streaming and you're just keeping the connection alive. And so knowing about chunked encoding or having a better understanding of that, we have a diagram that's like this
14:42
and this is kind of like a high level architecture of what we're doing at LinkedIn. And so we have the browser, we have the BPR and the BPR actually has a version of the Ember app inside of it which is the same Ember app that is running in the browser. And I'll talk about how we have those guarantees later
15:01
but just for now it's the same application that's running in the browser that's in the server. And then off the side we have an API server. So when a request comes in from the browser it goes directly to the BPR. In this case we're asking for LinkedIn profile 123.
15:23
And so what happens then is the BPR will almost immediately return with the head of the document. And so inside of this I'm not sure if you can read it but it is like the start of the HTML tag, it has any of your CSS that's inside of the head tag and then any scripts that you're gonna download.
15:43
So if you're using Ember CLI it's the vendor JS and the app JS. And so while you're doing this the browser can make the CDM request to get those assets before you close out the connection. So we call this, the other term for this type of technique is early flush
16:01
and what it means is that you flush early so you can start downloading assets in parallel. So after we sent down the initial chunk of HTML we actually use the fastboot visit API inside of the Ember app and we say,
16:22
hey Ember app I want you to visit profile 123 and in doing so the Ember app is going to route to profile 123 and some things are gonna happen. It's gonna probably want to try to make some API requests so when it does make an API request
16:41
we want to actually take that request and proxy that to our API server. And we actually wanted to do a little bit more performance work in this area by parallelizing more work. So Nick Iconis who is somewhere here
17:00
actually wrote this thing called Ember prefetch and what Ember prefetch does is that it introduces a new hook into your route and what that hook is is that it's non-blocking and what I mean by non-blocking is in a traditional Ember application you have the model hook and you return a promise out from the model hook and it's gonna wait
17:22
until that promise resolves to move on to, maybe you have nested routes, it'll move on to the next route and it'll do the same thing. You'll make an API call, the API call will come back and then move on and drive the state forward. With Ember prefetch you just call all the routes and so this is from a tool that we have internally
17:42
called the call tree and so the top one if you can see, this is running the Ember application inside of node and these are the requests that the API server is receiving. So the top one you can see all the calls that are done in serial where the bottom one has Ember prefetch installed and we're able
18:01
to parallelize some of the work that we wanna actually do. So this saves us processing time on the server and it will also save you time on the client. So that being said, we come back over with the data the API returns with the data
18:21
and we reenter the Ember application. Because we're using promises you could always have like a dot then on the end of the promise chain. So it means that you actually have to go back into the Ember application to resolve any potential pending promises. And so this is like normal Ember stuff. But at the same time we tee off.
18:40
And what we tee off with is a thing called the datalet and the datalet has all of the API request information inside of this datalet. So it's all of the data that you're going to need on the initial request when your Ember application boots up. And so we have a little library on the client
19:01
that acts kind of like a network proxy and it captures all these stream responses. And when the Ember app tries to attempt to make a request we match it up with a stream response and now your Ember application makes no HTTP Ajax requests when you initially load the app. And so what we see with this
19:22
is we get one to two seconds on initial render by embedding the API request into the index.html. And so I did a thing. I took the Ember fast boot server and I was able to kind of do this type of pattern.
19:42
I do not recommend that you put it in production as a complete proof of concept. But the end goal is that you'd be able to do something like this where you do Ember fast boot dash dash resource discovery. And all this would do is run the Ember application in the data center and embed the data into the index.html.
20:05
So I really think this is a pattern that we can build around and have shared infrastructure around. We've been doing this in production now for I think like six months. The other problem that we kind of had was we needed to serve the application.
20:23
Luke Melia, who announced me, also gave a really great talk last year about deploying and serving applications. And I would like to kind of share our approach now that you kind of have this complication of you're doing server side rendering. So how do you actually serve an app that way
20:42
and how do you actually deploy an app that needs a server component? You can't just rely on a CDN. And so to go into a little bit more detail, I'm gonna show what is actually happening inside the BPR. And I want to talk about this because I think this is a really good way on how you can leverage your existing technology,
21:03
be it like a Python stack or a rail stack, basically any other language that isn't node, and how you can leverage things like fast boot. So we went with what is called a sidecar architecture. And this was kind of championed by Netflix. They've done a lot of work in this area
21:21
and I think they have some libraries that allow you to do this. What it allows you to do is run your main process, so your existing application, side by side of the new technology that you want to use. So how this works is, and I'll get into more detail, is basically you can use both of these technologies
21:42
at the same time. So what happens is when a request comes in to the BPR, it hits this thing called the base page controller. The base page controller is responsible for, it's like a catch-all route or a star route that is just going to talk to this library called the renderer.
22:01
And what the renderer does is it takes the request and it calls into this other library called the process manager, and it associates that request to a node process. If you guys were in Felix's talk about how Electron works, it's very similar to how Electron works.
22:22
So the process manager is gonna spawn a renderer process, or a node process, which inside of it you have an Ember renderer. And you're gonna talk to this spawn process over what is called an IPC stream, or an inter-process communication stream.
22:40
And so this allows you to send messages between these two processes. And so the Ember app is going to issue some requests, like the Ajax request. And so what is actually happening inside of the Ember renderer, inside the Ember application, is we write an initializer that swaps out the Ajax method that knows about
23:05
how to make proxied API requests to our server. So it's seamless to the user. We just, at build time, we were able to produce a build that does the swapping. So we talk in between the node process
23:21
and the JVM process. And majority of the time, all the Ember app wants to do is just talk to the API server. So it's going to make a bunch of API requests like I had in the last diagram, and we are going to reenter into the Ember application to resolve any pending promises. But then finally, we have to return.
23:41
And so this is kind of like the life cycle, the BPR in much more detail. But I really think, like I mentioned before, it's a good way to leverage existing technology. So all of our networking libraries are all in the Java space, but we want to use the fast boot APIs in the node side.
24:04
And so finally, deployments. As I've said, we don't actually put the index.html into CDN. What we do is we have build infrastructure that basically, when you're building your Ember application,
24:21
and you're trying to commit some code, we run the Ember CLI build, and at the end, you have your normal Ember CLI assets. We publish those to a CDN, but then internally, we have a system to kind of associate your client-side application with a BPR instance. And so what we do is we take the assets
24:42
from the Ember CLI build, we gzip them up, and then we place them inside of the BPR, and the BPR is the actual deployable unit for us. So the BPR is actually a shared piece of infrastructure at LinkedIn. It's currently being ported to a library so that you can use the shared idea
25:02
across all the applications at LinkedIn, and this is kind of like what we're striving for. And so now I kind of want to talk a little bit about V8, and more particularly, any device that is going to run V8.
25:20
And so we have done a lot of work in this area, but one of the largest problems that we had was getting visibility into what Android phones are doing, or V8, anything that's running V8. And so while the profiler and the timeline tools are really great, they're samplers, which means that they're gonna look at
25:41
many different things and then kind of give you a general picture of the world. But we really wanted to have a high-level certainty that we were moving performance in the right direction. And so I work with Chris Selden, who is on the Ember core team, but he also works at LinkedIn.
26:01
And so he created this library called CrumTracing that basically can launch Chrome with all of the V8 flags on and JavaScript flags. And these are giving you very detailed numbers of what is actually going on in the JavaScript renderer inside of Chrome, or basically anything that's running V8.
26:23
And while you can do this by yourself, and I mean, this is I think how Chris normally works, but not everybody can parse what is coming out of the V8 logs. And so what he did was it parses all the V8 logs and gives you a much more readable format
26:41
of things like how long did you spend in functions, how long did it take to initial render, CPU usage, and so all these type of metrics that you really want to know when you're developing your application. And so this kind of helped us identify some areas around like script eval and how long it's gonna
27:04
actually take us to get it to initial render. So the Chrome team actually has a similar library. It's called Telemetry. And while it's great and it has a lot more benchmarks in it than we currently have with CrumTracing, it's all written in Python.
27:21
And what we wanted to do was create a tool that allowed our developers who primarily work in JavaScript to be able to iterate on that and add new benchmarks to CrumTracing. And we would also like to take community contributions for having a generic set of benchmarks. And so this doesn't have anything to do with Ember specifically, but it is a really great tool
27:43
for benchmarking your applications. So I think in 2016, there's a lot of interesting problems. A lot of them were kind of enumerated in the keynote talk this morning of like how are we gonna do offline, how are we gonna do server-side rendering with like rehydration, how do we get to like 50,
28:03
or 60 FPS animations on mobile devices. But I think as a community, we can continue to solve these types of problems in elegant and scalable ways. LinkedIn is climbing the same mountain with all of you, and we're really excited to be part of this community.
28:23
So I was gonna say one more thing, but I'm really hoping that oh yeah catches on, but maybe not. So we built an application. This is using all of the infrastructure that I just talked about. You can go to LinkedIn.com slash M. Sorry for the download the app interstitial.
28:41
Thanks. You can find me on Twitter at chathitella. My question is how do you pull the data out of the index.html? What do you have to do in your Ember app? So I don't know if you're able to see on the slide there.
29:02
So we, I don't think I can even pull it up. So what there is is that we inside, when we flush the head of the document, we have a little library that's called the BPR client. And when you are flushing the script tags down to the browser, it has a reference to that library.
29:22
So it calls like bpr.addresource or something like that. And all of those things get queued up into a big map on the client. And so the Ember application also has code inside of this to kind of know, hey, I need to drain some queue that's probably gonna be there when I boot the app.