STEVEN BAZYL: Hi, everyone.
And welcome to this week's "Google Developers Live" for
Google Drive.
I'm Steven Bazyl, joined here with Ali Afshar.
ALI AFSHAR: Hi.
STEVEN BAZYL: And today we are going to talk about a couple
of tips that you can use to increase the performance of
your application and your integration with Drive.
These are going to be a couple small things, but they are
pretty important and can actually have a pretty
dramatic impact on how your apps perform.
Let's start with a really simple one.
We have in the API a couple of the different operations, your
standard RESTful API.
And we have a verb for patch.
And for those who don't know what patch is, it's a way of
doing partial updates for a resource so you can only send
the modified fields.
Small bit of advice--
don't use it.
It's really simple.
Actually, the way the Drive API works, you can just do a
regular update on a resource with sparse fields, and it
will work fine.
Do you know why it actually ends up being more efficient?
ALI AFSHAR: So I have an idea, but just to get it correct.
You have files, and then you only have a few of the values
that you want to update in the--
STEVEN BAZYL: [LAUGHING]
Sorry.
Sorry, sorry.
I'm just trolling Ali here.
ALI AFSHAR: So you have a file that you want to update to
Google Drive.
And you've only got some of the parameters you want to
actually update.
So you've only got the title.
You've only got the description.
You don't have everything.
Now, that's what patch exists for is so that you can send
just a few of these.
But actually, in the Drive API, it doesn't make any
difference.
You may as well update with an impartial or sparse
file, as you say.
STEVEN BAZYL: Right, and this actually turns out to be kind
of a small internal implementation detail for how
patches work because we actually end up having to
re-read the entry back.
So it actually costs us a little bit more.
In terms of actual performance, it's not going to
make a huge difference for your application.
But it is a lot more resource-efficient for us if
you just do a regular update.
And I'm glad that we'll have some GDL bloopers for after.
We're just in a very giddy mood today.
So anyway, the next one is batching requests.
So batch is a way that you can bundle multiple requests
together into a single API request.
You can use it for all sorts of things, with the exception
of uploads.
But that aside, you actually still have a lot of options.
And there's a couple really good use cases for things,
like if you're listing the contents of a folder, and you
want to then expand things like the custom properties or
the ACLs on a file which require separate calls.
If you have, say, a page of files, say 20 files for a
page, you can then batch up the subsequent request to
expand out whatever additional properties you want.
And actually, it has a nice benefit in that it does a
couple things for you.
So one is there's a little bit less overhead in the HTTP
requests, so all the headers that you would normally send
plus the fact that you're usually setting up and tearing
down a connection each time.
There's a lot of overhead.
The other one is, while you can do the
parallel request yourself--
you can certainly do a whole bunch of basic requests and
then gather up the results--
the batch actually just handles all that for you.
And this is implemented in our client libraries in a way that
makes it super easy to do a whole bunch of parallel
requests together.
ALI AFSHAR: And that's interesting, because in our
old APIs, if you ever used the Documents List API, for
example, you could only batch the same
type of requests together.
So you could say, I only want to batch 50 Get requests in a
single batch.
But now with our newer Drive API, you can actually batch
different types of requests.
STEVEN BAZYL: That's true, right.
You could actually update 20 files all at the same time.
So if you wanted to add a description or some properties
to a set of files, you can actually do those very
efficiently.
One catch--
these do actually count as separate requests from a quota
perspective.
And while you can certainly do batches of up to 1,000
requests, if you were to try to do it, you'd actually start
to run into your QPS limits for an app and for a user.
But still, it's a useful technique for certain use
cases where you know that you need to do a whole bunch of
the operations, and you need to do them roughly at the same
time and do that very quickly.
So another one is partial updates.
This is something that we did a blog post
about just last week.
And this actually has probably the biggest impact on
application, performance, and your bandwidth utilization.
So one of the things you can do is, when you're calling
Drive API, you can [? be ?] a query parameter called Fields,
list which fields that you would like returned.
And I did some testing on this just using the common use case
of listing the contents of a folder and found that you
could actually get about--
for a common use case, about 90% reduction in bandwidth.
And so that's huge.
So it went from something like 380 K down to 30.
Actually, it was even less of that.
Throw in gzip compression, then it goes from 30 K down to
about 7, so it's actually pretty important.
And I've heard from a few people in the community that
this actually has a little bit of a financial impact, for
cases where you're buying bandwidth and so on.
ALI AFSHAR: I mean, that's the whole point of this.
Make fewer requests, that's going to cost you less.
Send less data, that's going to cost you less.
Receive less data, that's just going to cost you less.
So I mean, we don't want you to pay more
money for the stuff.
That's the main thing.
STEVEN BAZYL: And the nice thing is--
I mentioned gzip compression.
Gzip compression has a cost in terms of the CPU usage.
We certainly still encourage it.
But if you are very sensitive to CPU, then another way that
you can reduce your bandwidth is by limiting the amount of
data that you send back in the first place.
There are some upcoming changes we're working on in
the backend that will actually make this not just faster from
a bandwidth perspective, but actually faster from the
amount of time that it takes to actually execute the
queries, to serialize the data into a response.
And so over time, this is just going to get better
and better for users.
ALI AFSHAR: So right now on the backend, we fetch all the
data and then selectively send you some back.
And that's the problem there.
STEVEN BAZYL: Exactly.
And just the way things are stored, it's actually very
time-consuming to go and assemble all that data.
But now with these hints, we can do a lot of optimizations
to make sure that we get results back to you as a
developer a lot faster.
ALI AFSHAR: So if you just want to list the titles, the
title of the files in a list, you just ask for the title.
STEVEN BAZYL: Exactly.
If you did that, you'd probably save about 95% of the
actual data.
It would just be completely eliminated from the network.
ALI AFSHAR: And to see how to do that, check out
Steve's blog post.
STEVEN BAZYL: Yeah, it's really easy.
All the API clients support it.
And again, it's just a query parameter.
There's a little bit of an odd syntax because these are
structured responses.
So if you have nested collections or some syntax or
how you would enumerate which collections and which
properties of those collections.
But this is all documented pretty well on
developers.google.com.
The last one, which doesn't necessarily connect back to
performance quite as much, is just proper error handling.
So there's a couple different cases for errors.
So some of the common ones, you get things like, you're
unauthorized.
You may be rate limited, so that would be a 403 response.
And you also run into occasional 500 errors.
These aren't necessarily things that you can control.
When you hit a 500, it's usually some intermittent
error, a timeout, heavy load on our side.
But how you respond to those errors can actually have an
impact, particularly in the case of high-load situations.
So what are some of the strategies people should use
for retrying on errors?
ALI AFSHAR: So in general, retry on errors.
I mean, I think that's a general point.
Because sometimes, as you mentioned, intermittent errors
and that kind of thing.
But we, the API--
it's a massive distributive system.
And we kind of expect you to retry.
STEVEN BAZYL: Right.
But you don't want to just retry immediately, right?
ALI AFSHAR: No, no, exactly.
STEVEN BAZYL: Because otherwise, we're just going to
hammer the server, and things aren't going to improve.
ALI AFSHAR: So as always, you should use
an exponential backoff.
So try again, try again in an exponentially increasing
amount of time, add a little jitter, of course.
And yeah, just do it.
Usually, it will succeed.
And you'll see, if you check out Stack Overflow,
occasionally people do get these errors.
And they're fixed just by retrying.
STEVEN BAZYL: Yeah, exactly.
One thing is, don't--
on that initial retry, make sure you put in a delay.
It should be at least a second.
Obviously, if you're doing things in user time, you don't
want to go too long of a delay.
But if it's something more programmatic, you're doing a
background job, you can actually even back off a
little bit more aggressively and give the
system time to recover.
And the jitter is actually really important.
And for those who don't know this concept of jitter, it's
basically adding in some randomized
value into that delay.
So if you just did a fixed exponential backoff, you might
do a delay of 1 second, then 2 seconds, then 4
seconds, and so on.
The problem is that if you have a lot of threads doing
this and they all happen to hit the same error at the same
time, well, they're all going to retry at the same time.
And you end up in this kind of wave, the cycle of servers
just getting hammered by all of these
clients acting in lockstep.
Adding a little bit of randomization gives those
clients a little bit of time to differentiate and get on to
a different period for when they're going to retry and
start to smooth out the traffic a little bit more.
So a reasonable value could be maybe 10%.
Just pick a random value and then add or subtract.
But it'll make things recover a lot faster if you have those
types of things.
So are there any other things you can think of that would
help people?
So there's low-level things like gzip and so on that
people could do.
But those are usually taken automatically
by the client libraries.
ALI AFSHAR: So those are the things--
remember batch requests, catch errors, and retry.
Partial fetch here is really important, so passing the
fields parameter to just get back what you want.
And patch sounds like a good idea, but it's probably better
to just do an update, a partial update at the time.
But those are our things.
And remember why you do this.
It just saves you bandwidth.
It saves you time.
And sometimes it saves us time, which obviously isn't
your main concern.
But it just means you get the requests back quicker, which
is obviously going to be good.
You get better latency in your application.
So that's good.
STEVEN BAZYL: Yep.
So that's all for this week.
Next week, I am not entirely sure if we have
our topics set for--
that we may actually skip, but we'll be back certainly the
week after for our normal schedule with Apps of the Week
and hopefully, a few guests.
We'll actually be out next week.
And yeah, until then--
ALI AFSHAR: Thanks very much.
STEVEN BAZYL: --thank you all for coming.
ALI AFSHAR: Bye.