My GraphQL Performance Problem

Sdílet
Vložit
  • čas přidán 1. 01. 2020
  • I ran into a performance problem related to GraphQL. I go through how I debugged and fixed it.
    Links from video:
    / 1212392789637521410
    news.ycombinator.com/item?id=... ​

    ----
    Follow me online: voidpet.com/benawad
    #benawad
  • Věda a technologie

Komentáře • 128

  • @TheNewton
    @TheNewton Před 4 lety +54

    tl;dw 10:40 overfetching fields & 11:12 type-graphql performance, optimized by lowering results fetched and using beta branch of type-graphql

  • @porgeet
    @porgeet Před 4 lety +63

    Thanks for sharing, this type of content is extremely useful. Not many people share the process of figuring out a problem, very helpful. 10/10 would watch again.

  • @metropolis10
    @metropolis10 Před 4 lety +2

    Fantastic video. Thank you so much for showing step by step your debugging process of a problem. I always learn a ton when I watch someone else try to solve a problem!

  • @Frogquest
    @Frogquest Před 4 lety +8

    I find these types of videos where you troubleshoot actual problems to be incredibly enlightening. I don't think there's enough of this type of content. Bravo! I didn't quite understand the connection to type-graphql though TBH and would love it if you explained that a little more. Really appreciate following along with your thought processes though.

    • @bawad
      @bawad  Před 4 lety +1

      I'm using type-graphql to create my graphql schema, so one thing it does is wrap all my resolvers in some type-graphql code. That code apparently has some problems

  • @MrEmanuelherrera
    @MrEmanuelherrera Před 4 lety +1

    Thanks Ben for explaining and sharing the problem.

  • @pkop4
    @pkop4 Před 4 lety +45

    Points to one advantage of using Hasura, written in Haskel, and uses a meta-data engine that pre "compiles" types and queries, maps to efficient Postgresql queries...minimizing overhead/redundancy of both layers.

    • @uziboozy4540
      @uziboozy4540 Před 4 lety +3

      Didn't even know they did that under the hood.
      Maybe it's time to reconsider using Hasura instead of Prisma.

    • @cobalt2489
      @cobalt2489 Před 3 lety +1

      Or use diesel & actix with rust. To make your API goo BRRRRRRRR

  • @Butcheren0
    @Butcheren0 Před 8 měsíci

    Glad you figured it out. Facing a similar issue, our problem is that it is only occasionally slow without any perticular query seemingly causing it. This causes CPU to spike in our pods which again causes timeouts etc.

  • @scottamolinari
    @scottamolinari Před 4 lety +8

    Great content. Please continue showing problem solving processes like this. I think it's more valuable than straight tutorials.
    Ah, and can you post in Twitter about what results you got once you pushed to production? (if not another video)? :)

  • @boopfer387
    @boopfer387 Před 4 lety +3

    curious on if you messed with a Graph database like Neo4j?

  • @petecapecod
    @petecapecod Před 4 lety

    Great video thanks for showing us how to debug GraphQL requests

  •  Před 4 lety +10

    Hey Ben, great video. Personally I think that one of performance issues is certainly the overfetching. You shoud fetch only data needed for search component, not for recipe detail. Excited to see performance difference while not overfetching :)

    • @bawad
      @bawad  Před 4 lety

      yeah that was certainly part of the problem

    • @cklee_
      @cklee_ Před 4 lety

      @@bawad any way to lazy load the query for the recipe detail after the initial fetch for the search component?

    • @bawad
      @bawad  Před 4 lety

      @@cklee_ yeah that's what I'm planning on doing

    • @herohamp2
      @herohamp2 Před 3 lety +1

      What I did for one of my sites is launch the request to the load the data for a search result on over not on click, so that by the time the user clicks it has already been loaded and will be instant. That should keep the instant loads of recipes like shown here while reducing the graphql overhead

  • @Kanexxable
    @Kanexxable Před 4 lety

    how do you set up graph ql with the typescript complier ! Note I don't want to use type Graph QL i just want to use typescript as my compiler

  • @raka2958
    @raka2958 Před 4 lety

    Can someone recommend a project based course to learn javascript (+ ecosystem) ? Took one udemy course but abandoned it as it dragged too much

  • @ProjektArcadia
    @ProjektArcadia Před 4 lety

    It would be nice to see some more performance comparisons.
    The same queries with the current and beta type-graphql version, with and without overfetching and with both optimizations.

  • @justfly1984
    @justfly1984 Před 4 lety

    We have decided to use web-sockets on top of AWS API gateway. native, realtime, cross-browser support and pretty type-safe. We had multiple perf issues and caching issues on previous GraphQL project so this time we use good old REST and pure web-sockets.

  • @driziiD
    @driziiD Před 4 lety +11

    really impressive performance-tuning
    i learned a lot
    high-quality content as always

  • @ngneerin
    @ngneerin Před 2 lety

    This is the type of content missing from the web. Continue with such videos

  • @C493d
    @C493d Před 2 lety

    Was this really the solution or did you take any further steps after?

  • @DrPanesar
    @DrPanesar Před 4 lety +5

    Hi Ben. What version of type-graphql did you need to upgrade too?

    • @bawad
      @bawad  Před 4 lety

      0.18.0-beta.8
      edit: 0.18.0-beta.9 just came out with even more improvements

  • @vinayakshahdeo7578
    @vinayakshahdeo7578 Před 4 lety

    Ben can you help how to take a screenshot in react and append it as a file input automatically?

    • @bawad
      @bawad  Před 4 lety

      sorry, not sure how to do that

  • @arielsashcov99
    @arielsashcov99 Před rokem

    Hey Ben can you try Wundergraph?

  • @vsalbuq
    @vsalbuq Před 4 lety +1

    I don't understand what you do yet, but I will. That's why I've subscribed. I'm just exposing myself to your videos and some things are coming by osmosis.
    Until the end of the year I'll probably understand that. Thanks for the video, anyways.

    • @bawad
      @bawad  Před 4 lety

      if you're new to GraphQL, I recommend starting with graphql.org/learn/ and czcams.com/play/PLN3n1USn4xln0j_NN9k4j5hS1thsGibKi.html

  • @sinefinehabitarevolo
    @sinefinehabitarevolo Před 4 lety +1

    This is a great breakdown video. How were you able to get the query field breakdown to DataDog?

    • @bawad
      @bawad  Před 4 lety

      check out datadog APM they have a node.js lib

  • @jamesherrero7334
    @jamesherrero7334 Před 4 lety

    3:51 you mention that you're using apollo tracing, how did you make it give you that diagram?

    • @bawad
      @bawad  Před 4 lety

      That's Apollo platform

  • @alkismavridis1
    @alkismavridis1 Před 4 lety +4

    I think this is a very much library specific issue. GraphQL is a specification, not an implementation. There are lots of implementation libraries for it that target multiple programming languages and platforms. So, it would be more meaningful to say that this or that implementation is slow, not graphQL as a whole.
    We, for example, use graphQL mostly in java (the library is called graphql-java-tools) and we did not measure any significant overhead... 🙃
    Your solution for nodejs was great, though. We should inspect catefully our runtime implementations. Thanks for the video!

  • @aleksd286
    @aleksd286 Před 4 lety +1

    how did you test how fast you could md5 hash something?

    • @bawad
      @bawad  Před 4 lety +2

      console.startTime('md5')
      imgix.sign()
      console.endTime('md5')

  • @hdauven8434
    @hdauven8434 Před 4 lety +2

    Hey Ben, it would be interesting to see the performance difference between the regular GraphQL library and Type-GraphQL. That would show whether it really is the culprit of performance issues in your implementation.

    • @bawad
      @bawad  Před 4 lety +1

      yeah this would be good to do, I'm just too lazy to set it up in graphql-js
      here's a benchmark though github.com/MichalLytek/type-graphql/pull/488#issuecomment-564592663

  • @xmorse
    @xmorse Před 4 lety +7

    Probably a problem related to overuse of promises, every promise adds a lot of over head and the garbage collector has to remove all these allocated promises, every field in your type graphql schema is probably implemented as an async function

    • @bawad
      @bawad  Před 4 lety +2

      yep I think it is related to that

    • @BIELSIMON
      @BIELSIMON Před 4 lety

      Okay but what is the solution then, in nodejs since it is single threaded everything has to be async

    • @bawad
      @bawad  Před 4 lety

      one solution is to remove promises where stuff should just be sync

    • @BIELSIMON
      @BIELSIMON Před 4 lety

      Yes, makes sense. But don't you think that those cases are already (or should) be optimized automatically by the js engine? I'm no google engineer and I think I'd know how to do it...

    • @BIELSIMON
      @BIELSIMON Před 4 lety

      I am very interested in this because this can basically determine whether it is possible to make a truly performant graphql api. If it turns out that it is not, graphql will be delegated to edge cases such as specific public facing apis and apis for mobile devices or network constrained environments. I really like graphql and would like this not to be the case though.

  • @Xhisorz1
    @Xhisorz1 Před 4 lety

    Thats a nicu, my Dude.

  • @LucasBatistussi
    @LucasBatistussi Před 3 lety +3

    BFF (Back End For Frontend) pattern says hi 🙋

  • @vorname1485
    @vorname1485 Před 4 lety

    when you mentioned md5 and request count, i was sure not this, cause md5 is made to be fast, which is also a reason why its unsafe to hash passwords with it, like many did and do (bruteforce is easier because less time needed to create hash).
    17ms on simple description: string default resolver sounds heavy. I bet the default resolver on the library is poorly optimized (or was).
    Is there any way in the library to set own default resolver?

    • @bawad
      @bawad  Před 4 lety

      idk if the tracing is getting fooled some how, but the default resolver should do nothing

    • @BIELSIMON
      @BIELSIMON Před 4 lety

      I think it is waiting for other promises to resolve, it isn't using 17ms of cpu time probably. It's a recurring issue I find with js devtools. It should indicate which promise (or promises) it is awaiting

  • @OBLIVIOUSKARI
    @OBLIVIOUSKARI Před 4 lety

    Can you upload a video to let us know if you find out more or an update happens!?

    • @bawad
      @bawad  Před 4 lety

      follow me on twitter.com/benawad I'll keep you posted

  • @rtorcato
    @rtorcato Před 4 lety

    for the foreach callback are you setting it to async?

    • @bawad
      @bawad  Před 4 lety

      I think the forEach is something the internals of graphql does

    • @rtorcato
      @rtorcato Před 4 lety

      @@bawad ok this link explains what could be the problem with the foreach riptutorial.com/javascript/example/7746/looping-with-async-await

    • @bawad
      @bawad  Před 4 lety +1

      I'm not sure what the code looks like, but you can still use forEach and avoid that
      const promises = [];
      arr.forEach(item => {
      const p = asyncTask(item)
      promises.push(p)
      });
      const results = await Promise.all(promises)

    • @paweld.9542
      @paweld.9542 Před rokem

      @@bawad or you can do like that, more elegant way : const results = await Promise.all(arr.map((item) => asyncTask(item))) 😉

  • @InfoPaste
    @InfoPaste Před 4 lety

    Could you do a video about lunching your platform. I plan to do the same soon and create tips or advice would be great

    • @bawad
      @bawad  Před 4 lety +1

      haven't done much to launch it yet, only product hunt

    • @31redorange08
      @31redorange08 Před 3 lety

      @@bawad He said lunch, not launch.

  • @unlimitself
    @unlimitself Před 4 lety +10

    This is why I started using GoLang. The performance is mind blowing. Other static typed close to C languages are also good.

    • @andresmontoya7852
      @andresmontoya7852 Před 4 lety +2

      No, I think the error is that GraphQL resolves the problems that http 1.1 had. That's why serverless options works better, because they work over http 2 or 3.

    • @uziboozy4540
      @uziboozy4540 Před 4 lety +1

      I just can't stand looking at Go code.. A functional combination of C and Python, but with terrible type support..
      If you're really looking for a mind blowing language, master Rust instead.

    • @unlimitself
      @unlimitself Před 4 lety

      @@uziboozy4540 Sure. Rust is great as well. That is why, I mentioned any "Other static typed close to C" language.

  • @yah3136
    @yah3136 Před 4 lety +3

    Don't overfetch, save the planet

  • @Jossnaz
    @Jossnaz Před 4 lety

    actually if type checking is such an issue, why type check? Isn't it commmon nowadays to just strip typescript out and run pure js code?

    • @estranhokonsta
      @estranhokonsta Před 4 lety +2

      I think he meant type checking by Graphql, not typescript. Typescript is normally always pre-compiled to pure js. But Graphql is a 'typed API'.

    • @Jossnaz
      @Jossnaz Před 4 lety

      @@estranhokonsta cant you strip typescript entirely during the build process? you lose runtime type checking yes, but you get 2 advantages: fast build time, and faster performance. I just assume type graphql makes heavy use of typescript. What checks do have to be done when doing a read? is type graphql double checking the database columns on a read? "is it really an integer?" that'd be stupid

    • @bawad
      @bawad  Před 4 lety

      ​@@Jossnaz
      > cant you strip typescript entirely during the build process?
      yes
      > is type graphql double checking the database columns on a read? "is it really an integer?"
      It's not type-graphql, but graphql checks each field to make sure it's the expected type

    • @estranhokonsta
      @estranhokonsta Před 4 lety

      @@Jossnaz The truth is that modern dev can be so confusing that it let's one doubt many things. All this because modern apps and tech are complex and too many faceted.
      Just in this one project there must be typeOrm, TypeGraphQL (i assume) Typescript, GraphQL, etc And all of them have some relation to types.
      TypeORM and TypesGraphQL are related as they use types, classes and decorators of Typescript and are more for ease of development for the programmer (although they no doubt each introduce overhead in the prod code).
      GraphQL also use its own typing system completely unrelated to Typescript and heavily influence the prodution code.
      And so many other layers of complexity.
      But just thinking about creating a modern and minimally feature rich app with just vanilla javascript... Hell will not be on the creation part, as it is not so impossible as that. The real suffering will appear when one has to maintain the code. It is difficult as it is for the ones who have created the project, never mind the ones who comes afterward.

    • @Jossnaz
      @Jossnaz Před 4 lety

      @@estranhokonsta well its like a thing of javascript that everything is so volatile. And if you update one thing, all of the sudden all breaks. It's certainly an anti pattern to use the standard versioning style in the package.json imho. Things break soooo quickly. Upside is that javascript is very innovative it seems... good graphql libraries for php? I've seen one with 3k stars... thats really nothing. The question I was wondering about as well is whether graphql really, really is worth it? do you have soooo many rest endpoints otherwise, really? so many calls? usually a bunch of crud + search thats it. I dont know man. I havent seen the value yet

  • @estranhokonsta
    @estranhokonsta Před 4 lety +1

    Debugging is tiresome and frustrating :(
    To me what jumps right away is the same as you said: the huge garbage collection. It still took one fifth of the total time from what you showed us.
    To debug it, first i would only use one request (the one that is causing the performance problem) and not so many of them. And i also wouldn't take out anything form it, including the postgress queries. This to avoid some others non-linear problems that can obscure the data. Then only after that one can begin to add or cut thing as needed.
    The main thing to check in those situations is if the bug comes from our code or from some other modules.
    What i would do is go up from there to see in which field resolve it originated (since it is a graphql API). Probably checking the 3 "(anonymous)" calls above the 'applyMiddleWares' and see if the resolve functions are from the same fields. Then you can try and dig dipper into them with some test code or just logging the timestamps and number of time they are called and also using normal breakpoints if needed.
    The garbage collection seem to be called by tslib.js which is supposed to 'manage' the typescript helpers. Probably a sign of some problem in the decorators or something related? Async await may be involved. Does it needs a try catch for some reason? Or some polyfill that is not behaving correctly with your javascript version and your node version?
    Or it could simply be that you only need a simple if statement to check if some value exist?
    Or some graphql types/fields may have some circular dependency that is not dealt appropriately?
    Debugging is no doubt the worst part of programming. Fortunately at the end of the video, you presented a possible solution. Who knows if it is the right one, but it works and that is what helps preserve the sanity of the normal everyday programmer.

  • @OBLIVIOUSKARI
    @OBLIVIOUSKARI Před 4 lety

    Thanks I’ll try to update it. I had the same issue and ended up creating a database table that contained preprocessed data. Before that, my resolvers we’re taking 6 seconds to complete.

    • @OBLIVIOUSKARI
      @OBLIVIOUSKARI Před 4 lety

      I wonder if it were better sticking with Apollo but typegraphql and TypeORM api is just too good

    • @bawad
      @bawad  Před 4 lety

      yikes 6 seconds is a looooooooooooooooong time
      yeah I really like the typegraphql/typeorm api, so I'm hoping typegraphql can make some improvements to its performance

    • @OBLIVIOUSKARI
      @OBLIVIOUSKARI Před 4 lety

      Ben Awad it was crazy because each step on it’s own we’re near instant. But combined 6 seconds. Hopefully it gets better, it’s my fav library when used with typeorm

    • @bawad
      @bawad  Před 4 lety

      @@themanlihood how are you annotating fields? Do you use decorators? Can I use 1 class for both my graphql type and typeorm model?

  • @eduriseworld
    @eduriseworld Před 4 lety +29

    Extremely useful content Ben.
    Thank you for sharing. ❤️
    Please take a look at our Project Based React tutorials as well.
    Keep doing the great work 👍

    • @bawad
      @bawad  Před 4 lety +2

      Any particular kind of project you had in mind?

    • @eduriseworld
      @eduriseworld Před 4 lety

      Hey @@bawad, yes we do have a bunch of project ideas for tutorials specifically. Which will help people get up and running with React and also newer tech such Apollo which you're very good at. So keep doing the great work and we will keep moving forward as well.

    • @bawad
      @bawad  Před 4 lety +16

      oh lmao this is an advertisement, I thought you were wanting to see me make more project based react tutorials

  • @romanext921
    @romanext921 Před 2 lety

    Why not just cache each recipe? It's okay if it takes 500ms, cause most of the time it would be instant

  • @elgunlee
    @elgunlee Před 4 lety +1

    Use Golang's GraphQL libraries for server

  • @rodmanswanston3320
    @rodmanswanston3320 Před 4 lety

    Did you try deduplication?

    • @bawad
      @bawad  Před 4 lety

      nope, have you had success with that? At what level do you dedupe?

    • @BIELSIMON
      @BIELSIMON Před 4 lety

      Deduplication in the request level? Data rows? Or like memoizing with data loaders?

  • @eyesight2073
    @eyesight2073 Před 3 lety

    😻😻😻😻

  • @Jossnaz
    @Jossnaz Před 4 lety

    a possible solution to avoid such huuuuge queries that arent really needed is to create enriched views. Inserts and deletes will be a bit slower though...

  • @dealloc
    @dealloc Před 4 lety +1

    For efficient searching, especially considering you have a hierarchy of data that can be searched for, it would be more efficient to use something like Elasticsearch, Solr or Algolia (as a service). GraphQL isn't ideal for free form search, as you will have to do all the optimization yourself, and even then, GraphQL has the overhead it has to process the data before returning it.
    Now, this only makes sense as your app grows, so there's no need to be on the edge on it, but just wanted to pitch in!

    • @bawad
      @bawad  Před 4 lety

      Wouldn't I still go through GraphQL to query Elasticsearch or do you recommend directly talking to elastic?

    • @dealloc
      @dealloc Před 4 lety

      @@bawad As with authentication services, it is best to have separate endpoints for those types of services.
      I recommend that you create an endpoint (or separate service with its own endpoint, whichever you prefer) to handle requests for search which then in turn uses the search mechanism of your choosing (e.g. Elastic).

  •  Před 4 lety

    Hi, would it be worthy to try using server side rendering (in the case you are using SPA).

    • @bawad
      @bawad  Před 4 lety

      ssr wouldn't change anything in this case

  • @Oswee
    @Oswee Před 4 lety

    For me watching this conclusion is only one... i should stay away from GraphQL forever as i am working with large tabular data sets mostly.

  • @jacobebey7019
    @jacobebey7019 Před 4 lety

    It's the apollo tracing... It's hefty and should never be used in production. If you disable that and run the profiler, be amazed.

    • @bawad
      @bawad  Před 4 lety

      I'm not using apollo tracing in production, just tried it to test locally

  • @somedatussr4323
    @somedatussr4323 Před 3 lety

    I don't mean to be rude but this is why you shouldn't use javascript for a production backend. You should have chosen something like spark-jobserver with python. The performance would be much better and you would have spark's data analytics tools.

  • @thomasczthomash1859
    @thomasczthomash1859 Před 4 lety +2

    Solve all your GraphQL performance problems by upgrading to REST APIs.

    • @bawad
      @bawad  Před 4 lety

      big brain plays

  • @darkpill
    @darkpill Před 3 lety +1

    Best way to solve any GraphQL problem. Don't use GraphQL! Problem solved!

  • @RockuHD
    @RockuHD Před 4 lety

    That garbage collection is HUGE. Maybe you should go in and edit the field resolver/applymiddlewares. Make it reuse variables rather then creating a new variable each time.

    • @bawad
      @bawad  Před 4 lety

      I would, but I didn't write that code. It's from type-graphql

  • @AmstradExin
    @AmstradExin Před 4 lety

    Performance problems? Assembler. (:

  • @tibordigana2551
    @tibordigana2551 Před 4 lety +2

    Young developers repeat 15 years old architectural problems. Server/Client side logic. Instead of building DTO objects on the server side, they cope with bunch of security and performance problems on the client side. Same with the old Asp .Net. Querying 20 objects must be fast like the hell and i did not mention that the database must be very large cca 100 million records.

  • @Cassp0nk
    @Cassp0nk Před 4 lety

    Surprising you are over fetching as that’s basically what graphql is there to avoid. Otherwise you may as well have used rest. In fact with your apparent problem domain it looks like graphql is probably just adding complexity and latency and thus over engineering.

    • @bawad
      @bawad  Před 4 lety +1

      In this case, I was over fetching on purpose to simplify some logic on the frontend
      > Otherwise you may as well have used rest
      yeah I've been thinking about that lately

  • @socialblade7751
    @socialblade7751 Před 4 lety +2

    GraphQl for small application, my advice to use Rest API or Grpc (Best solution, very fast) for production ..

    • @paraluchs_
      @paraluchs_ Před 4 lety +1

      But why? Huge companies like Facebook, Twitter, Airbnb and Twitch ditched REST for GraphQL.
      As mentioned in the Video the problem was TypeGraphQL and transfer of huge amounts of data (which should always be avoided).

    • @JohnDoe-ji1zv
      @JohnDoe-ji1zv Před 4 lety +1

      pharti77 nobody abandoned REST! REST will be still be there for a long time yet.

    • @paraluchs_
      @paraluchs_ Před 4 lety

      @@JohnDoe-ji1zv I also agree with that. I use both.

  • @DavidSmith-ef4eh
    @DavidSmith-ef4eh Před 4 lety +2

    Another reason not to use graphql

  • @mydisk2859
    @mydisk2859 Před 2 lety

    Use apollo-server with js simply no n0nsense