My GraphQL Performance Problem

Поділитися
Вставка
  • Опубліковано 1 січ 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
  • Наука та технологія

КОМЕНТАРІ • 128

  • @porgeet
    @porgeet 4 роки тому +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.

  • @TheNewton
    @TheNewton 4 роки тому +54

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

  • @metropolis10
    @metropolis10 4 роки тому +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 4 роки тому +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  4 роки тому +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 4 роки тому +1

    Thanks Ben for explaining and sharing the problem.

  • @scottamolinari
    @scottamolinari 4 роки тому +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)? :)

    • @bawad
      @bawad  4 роки тому +1

      will do

  •  4 роки тому +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  4 роки тому

      yeah that was certainly part of the problem

    • @cklee_
      @cklee_ 4 роки тому

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

    • @bawad
      @bawad  4 роки тому

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

    • @herohamp2
      @herohamp2 3 роки тому +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

  • @Butcheren0
    @Butcheren0 8 місяців тому

    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.

  • @pkop4
    @pkop4 4 роки тому +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 4 роки тому +3

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

    • @cobalt2489
      @cobalt2489 3 роки тому +1

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

  • @ProjektArcadia
    @ProjektArcadia 4 роки тому

    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.

  • @petecapecod
    @petecapecod 4 роки тому

    Great video thanks for showing us how to debug GraphQL requests

  • @boopfer387
    @boopfer387 4 роки тому +3

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

  • @driziiD
    @driziiD 4 роки тому +11

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

  • @Kanexxable
    @Kanexxable 4 роки тому

    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 4 роки тому

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

  • @sinefinehabitarevolo
    @sinefinehabitarevolo 4 роки тому +1

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

    • @bawad
      @bawad  4 роки тому

      check out datadog APM they have a node.js lib

  • @ngneerin
    @ngneerin 2 роки тому

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

  • @DrPanesar
    @DrPanesar 4 роки тому +5

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

    • @bawad
      @bawad  4 роки тому

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

  • @vsalbuq
    @vsalbuq 4 роки тому +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  4 роки тому

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

  • @alkismavridis1
    @alkismavridis1 4 роки тому +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!

    • @bawad
      @bawad  4 роки тому +1

      agreed

  • @justfly1984
    @justfly1984 4 роки тому

    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.

  • @hdauven8434
    @hdauven8434 4 роки тому +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  4 роки тому +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

  • @vinayakshahdeo7578
    @vinayakshahdeo7578 4 роки тому

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

    • @bawad
      @bawad  4 роки тому

      sorry, not sure how to do that

  • @jamesherrero7334
    @jamesherrero7334 4 роки тому

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

    • @bawad
      @bawad  4 роки тому

      That's Apollo platform

  • @arielsashcov99
    @arielsashcov99 Рік тому

    Hey Ben can you try Wundergraph?

  • @aleksd286
    @aleksd286 4 роки тому +1

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

    • @bawad
      @bawad  4 роки тому +2

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

  • @InfoPaste
    @InfoPaste 4 роки тому

    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  4 роки тому +1

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

    • @31redorange08
      @31redorange08 3 роки тому

      @@bawad He said lunch, not launch.

  • @OBLIVIOUSKARI
    @OBLIVIOUSKARI 4 роки тому

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

    • @bawad
      @bawad  4 роки тому

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

  • @vorname1485
    @vorname1485 4 роки тому

    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  4 роки тому

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

    • @BIELSIMON
      @BIELSIMON 4 роки тому

      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

  • @C493d
    @C493d 2 роки тому

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

  • @xmorse
    @xmorse 4 роки тому +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  4 роки тому +2

      yep I think it is related to that

    • @BIELSIMON
      @BIELSIMON 4 роки тому

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

    • @bawad
      @bawad  4 роки тому

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

    • @BIELSIMON
      @BIELSIMON 4 роки тому

      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 4 роки тому

      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.

  • @LucasBatistussi
    @LucasBatistussi 3 роки тому +3

    BFF (Back End For Frontend) pattern says hi 🙋

  • @Xhisorz1
    @Xhisorz1 4 роки тому

    Thats a nicu, my Dude.

  • @rtorcato
    @rtorcato 4 роки тому

    for the foreach callback are you setting it to async?

    • @bawad
      @bawad  4 роки тому

      I think the forEach is something the internals of graphql does

    • @rtorcato
      @rtorcato 4 роки тому

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

    • @bawad
      @bawad  4 роки тому +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 Рік тому

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

  • @estranhokonsta
    @estranhokonsta 4 роки тому +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.

  • @yah3136
    @yah3136 4 роки тому +3

    Don't overfetch, save the planet

  • @OBLIVIOUSKARI
    @OBLIVIOUSKARI 4 роки тому

    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 4 роки тому

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

    • @bawad
      @bawad  4 роки тому

      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 4 роки тому

      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  4 роки тому

      @@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 4 роки тому +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  4 роки тому +2

      Any particular kind of project you had in mind?

    • @eduriseworld
      @eduriseworld 4 роки тому

      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  4 роки тому +16

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

  • @Jossnaz
    @Jossnaz 4 роки тому

    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 4 роки тому +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 4 роки тому

      @@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  4 роки тому

      ​@@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 4 роки тому

      @@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 4 роки тому

      @@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

  • @elgunlee
    @elgunlee 4 роки тому +1

    Use Golang's GraphQL libraries for server

  • @unlimitself
    @unlimitself 4 роки тому +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 4 роки тому +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 4 роки тому +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 4 роки тому

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

  • @rodmanswanston3320
    @rodmanswanston3320 4 роки тому

    Did you try deduplication?

    • @bawad
      @bawad  4 роки тому

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

    • @BIELSIMON
      @BIELSIMON 4 роки тому

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

  • @eyesight2073
    @eyesight2073 3 роки тому

    😻😻😻😻

  • @dealloc
    @dealloc 4 роки тому +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  4 роки тому

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

    • @dealloc
      @dealloc 4 роки тому

      @@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).

  • @Jossnaz
    @Jossnaz 4 роки тому

    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...

  • @romanext921
    @romanext921 2 роки тому

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

  •  4 роки тому

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

    • @bawad
      @bawad  4 роки тому

      ssr wouldn't change anything in this case

  • @Oswee
    @Oswee 4 роки тому

    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.

  • @somedatussr4323
    @somedatussr4323 3 роки тому

    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.

  • @jacobebey7019
    @jacobebey7019 4 роки тому

    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  4 роки тому

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

  • @thomasczthomash1859
    @thomasczthomash1859 4 роки тому +2

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

    • @bawad
      @bawad  4 роки тому

      big brain plays

  • @RockuHD
    @RockuHD 4 роки тому

    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  4 роки тому

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

  • @darkpill
    @darkpill 3 роки тому +1

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

  • @AmstradExin
    @AmstradExin 4 роки тому

    Performance problems? Assembler. (:

  • @tibordigana2551
    @tibordigana2551 4 роки тому +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 4 роки тому

    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  4 роки тому +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 4 роки тому +2

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

    • @paraluchs_
      @paraluchs_ 4 роки тому +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 4 роки тому +1

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

    • @paraluchs_
      @paraluchs_ 4 роки тому

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

  • @DavidSmith-ef4eh
    @DavidSmith-ef4eh 4 роки тому +2

    Another reason not to use graphql

  • @mydisk2859
    @mydisk2859 2 роки тому

    Use apollo-server with js simply no n0nsense