Transcript
[ Music ]
[ Applause ]
>> Good morning, ladies and
gentlemen.
How many of you are here for the
first time at WWDC?
That's fantastic.
It's great to see so many new
faces every year.
My name is Stuart Cheshire.
And we're going to be talking
about networking.
I'm going to start by covering
some topics that affect the
performance of your app.
There's hardly an app that
exists today that doesn't make
use of networking.
And getting the best performance
out of the network is really
important.
We're going to cover some
technologies here that help you
get the best performance.
We're also going to cover some
tips and tricks and guidance
about how to make the best use
of Apple's APIs, a little bit of
news about new technologies on
the horizon, and then my
colleague Jiten will go into
detail on URLSession.
Let's start off with a state of
the Internet update.
Earlier this year, we hit a
total of 4 billion people using
the Internet.
That's more than half of the
world's population.
And we're used to Internet usage
doubling and doubling.
Clearly when we passed halfway,
the number of people on the
Internet can't keep doubling, so
that growth is slowing down but
that doesn't mean Internet
growth is slowing down.
There's a lot of growth in
machine-to-machine
communications, Internet of
Things, Smart Homes.
There's still a lot of growth in
places like India and China.
And there is a lot of people who
have never owned a desktop
computer who may never own a
desktop computer.
Their primary computing and
communication device is their
Smartphone.
And a lot of those Smartphones
are still using 2G networks.
I'm sure most of us in this room
are fortunate enough to live in
places and work in places where
we build our apps where we have
fast LTE networks.
And that can be a handicap
because if you build your app so
it works well in LTE, it may
perform very, very badly on 2G.
One of your competitors,
somewhere else in the world, who
builds an app that works great
on 2G is going to be fantastic
on LTE.
So we have a tool to help
everybody mimic some of the
properties of these slower
networks and that's Network Link
Conditioner.
You should build your app
running Network Link Conditioner
right from the start.
Don't think you can add in
performance at the end because
it's too late.
Always, always, always run and
test your app using Network Link
Conditioner and that way if you
make a programming mistake that
has horrible performance
implications, you see it right
away and you can fix it right
away.
Use tools like Wireshark and
tcptrace to understand the
network performance of your app.
It's a lot like using
Instruments to look at memory
and CPU usage.
If you haven't seen tcptrace, it
is a wonderful tool that
produces graphs like this that
let you see at a glance what's
going on, on the network.
If you want to learn more about
that, check out the video from
three years ago.
IPv6 usage continues to grow.
Why is that important?
It's important because IPv6 is
shown to have better performance
than IPv4.
And if you care about
performance, you want to make
sure not just your app but the
service your app is talking to
support Native IPv6.
Some places in the world are
doing better in this respect
than others.
In the US, we're now up to 87%
of mobile carriers offering
IPv6.
Other places like India are
doing pretty well too.
And let's focus a bit more on
India.
Here is some data that the
networking team at Apple
gathered earlier this year about
net TCP connection setup time
and ongoing round-trip delay on
cellular networks in India.
The blue line is IPv6.
And if we, for example, look at
the 75th percentile, we can say
75% of TCP connections over v6
are set up in less than 150
milliseconds.
The comparable number for IPv4
is worse than 325.
It's more than twice as slow.
So if you want fast, responsive
applications for your users, get
on IPv6 if you're not already.
Another technology that improves
performance by reducing packet
loss and retransmission is
Explicit Congestion
Notification.
We've had this enabled by
default in macOS and iOS for
some years now so you don't need
to do anything on your
application to take advantage of
this.
Do make sure your service
supports ECN.
In a survey we did of the Alexa
top million websites, we found
last month we're now up to 77%
of the Alexa top million
services supporting ECN, which
is a big improvement compared to
a few years ago.
Another technology that helps
improve performance and
resilience of your connections
is Multipath TCP.
Quite often, the user may make a
connection in their office on
Wi-Fi and then they walk outside
and they lose the Wi-Fi signal.
Now with traditional TCP, the
connection is broken.
You have to reconnect.
You have to start again.
Multipath TCP makes its packet
routing decisions on a per
packet basis not per connection,
so it can switch that connection
live to a different interface.
We talked last year about how to
enable this in your application.
And, of course, check with your
server operators to make sure
your servers are supporting
Multipath too.
We recently did a survey of the
mobile carriers that Apple works
with around the world and right
now 78% of their networks work
with Multipath TCP.
Only 22% of carriers are still
blocking Multipath connections.
TCP Fast Open is a technology
that lets you avoid the normal
round-trip delay of the TCP
connection set up.
TCP Fast Open lets you put your
initial data in with the TCP
connection set up packets.
You can check out more details
of that from our video from
three years ago.
And check with your server
operators to make sure that your
servers support TCP Fast Open.
Now moving on to some new news.
There is a technology that many
of you will have heard of called
Quick.
Quick is a new transport
protocol, the first serious
candidate in 30 years for a
successor to replace TCP.
It started off as an experiment
by some engineers at Google.
That experiment proved
successful.
It has now been adopted as an
IETF work in group item for
standardization.
Apple engineers are
participating in that.
In fact, we have engineers right
now at the Quick meeting taking
place in Sweden.
This is not yet ready for prime
time.
The standard is not finished,
but Apple is working on it.
As soon as it is ready, you can
expect to see Apple API
supporting that.
Continuing in the theme of
performance, we observed some
behavior that's very common.
Lots and lots of websites and
Internet services use pretty
short lifetimes on their DNS
records.
And they do this because if a
data center goes down, they want
to be able to update the DNS and
very rapidly direct traffic to a
different data center.
The problem with this approach
is you're paying a performance
cost for something that almost
never happens.
Data centers very rarely go
down.
And what this means is every
time a DNS address record is
expired, your client has to
spend another round-trip delay
waiting for the response from
the DNS server, which is the
same as what it knew already
last time.
So thinking about this, we
realized and optimization we
could do.
If you pass the flag to opt into
this new behavior, then when you
do a DNS query, if we have a
stale, expired answer in the
cache, we will give that to you
immediately while in parallel,
at the same time, doing the
normal DNS query we would have
done anyway.
If the answer comes back the
same, as we predict it will
almost always, everything is
fine, you just saved a
round-trip time and got your
connection started faster.
If the answer comes back as a
different address, we will then
give another asynchronous
notification to your client that
there's a new address available
which it should also try.
And to make use of this, you
have to use it in conjunction
with Happy Eyeballs algorithm.
That means your racing multiple
connections in parallel.
You're trying IPv4, IPv6,
multiple addresses, multiple
interfaces.
If that sounds like a lot of
work and it's hard to get right,
you're absolutely correct.
It is a lot of work.
Stay after the break and we will
tell you about some new APIs
that let you take advantage of
this without doing all the hard
work yourself.
Now moving on to some guidance.
We have seen a common pattern
that many developers use
SCNetworkReachability as a
preflight check.
They want to predict the future.
They want to know whether the
next network operation they do
will succeed or fail.
And, unfortunately, predicting
the future is always a hard
thing to do.
You may have connectivity now
but two seconds from now the
user has walked out of the
building and you've lost the
Wi-Fi signal.
So there is no way to guarantee
whether a future operation will
succeed.
And we see this pattern where
they check.
The preflight says yes.
They try it.
They fail.
They go back.
They check again.
This also is a lot of work, a
lot of [inaudible], a lot of
difficult things to get right
including networks with proxies.
We can handle that for you.
The better way to do this is
just make a connection using the
waitsForConnectivity option.
You can learn more about that
watching last year's video.
What this means is if you want a
connection, you tell the system
I want a connection.
Now if you can, later if not.
If the device is in airplane
mode, then when it's out of
airplane mode your connection
will succeed.
That is much easier than
building the retry loop
yourself.
There is one case we've seen
with developers which does make
sense which is if you're going
to have the user answer a lot of
information in a form, you may
not want to waste the user's
time if you have good reason to
believe that may later fail.
If that is the use case you care
about, stay after the break
because we have a new way to do
that that's much better.
Security remains important, as
always.
After ten years of using TLS
1.2, the Internet is now ready
to move to its successor, TLS
1.3.
It has a number of improved
security features.
It has reduced connection setup
time, similar to TCP Fast Open.
That standard is now final.
The final draft was approved for
publication by the Internet
Engineering Steering Group
earlier this year.
We are waiting for the actual
published document to come out
of the RFC Editor.
And when that does, we'll be
turning on TLS 1.3 by default.
Right now in your seed, it's not
turned on by default.
You can use the instructions
here on iOS or macOS to enable
TLS 13 in your applications.
And we encourage you to do this
right away because later this
year when TLS 1.3 is turned on
by default, you don't risk
problems with your service not
being compatible.
So test them right now to make
sure everything will go smoothly
when the switchover happens
later this year.
Another element of security
that's new is certificate
transparency.
You've probably heard cases
where certificate authorities,
either through malice or
incompetence, issue rogue
certificates to entities that
they should not.
The solution to this is
something called certificate
transparency logs.
Every legitimate certificate
authority now issues a public
statement of every certificate
it issues.
And those are recorded in public
logs for anybody to inspect.
And this means that if a rogue
certificate authority issues a
bogus certificate, if it
publishes it, they'll
immediately get caught.
And if they don't publish it,
they'll be caught by the client.
This is the setup you're
probably familiar with.
The new entity here is the log.
When a certificate authority
issues a certificate to a
server, it also records that
with the log and the log gives
the server a signed affidavit
that its certificate has been
publicly recorded.
And then when the client
connects, the server can give
all that information to the
client and the client can verify
that not only is this a signed
certificate, it is a publicly
logged signed certificate.
Now suppose we have a rogue
certificate authority that
doesn't publicly expose the
rogue certificates it's issuing.
The client will reject that
because it doesn't have the
affidavit to attest to it being
recorded in a public log.
Starting later this year, we
will be enforcing this.
All newly issued TLS
certificates must include the
verification that they are
publicly logged.
And if they're not, then the
client will reject it.
Your apps don't need to make any
changes, but if you have
tailored certificates for your
servers, make sure that your
certificate authority is
recording them in the public
certificate transparency logs.
Now we have a bit of news for
hardware developers.
The Bonjour Conformance Test is
a tool that lets you verify that
your hardware devices implement
Bonjour correctly.
You need to run this test if you
want to use the Bonjour
trademark name and logo on your
packaging.
You need to run this test if you
want to bundle the Bonjour for
Windows installer with a Windows
application.
And if you want to use the
AirPrint, AirPlay, CarPlay,
HomeKit logos on your packaging,
passing the Bonjour Conformance
Test is a part of the logo
licensing process because
reliable Bonjour is an essential
part of those products.
But more importantly, the value
of running the Bonjour
Conformance Test is it helps you
improve the quality of your
products and that makes them
more reliable which makes your
customers happy which makes your
customers not return the product
to the store because they can't
make it work.
And that's what your customers
want.
That's what you want.
And that's what we want.
We want happy customers having a
wonderful time with products
that work reliably.
Now I want to cover API choices.
Thirty years ago we had BSD
Sockets.
And it was a great API 30 years
ago.
But 30 years ago we didn't have
mobile computers in our pockets.
We didn't have wireless
networking.
We didn't have IPv6.
We didn't have many computers
with more than one network
interface.
If you had an Ethernet port on
your computer, that was a fancy
computer.
Now 4 billion people around the
world have a multi-homed IPv6
wireless battery-powered
computing device that does power
management and goes to sleep to
save energy.
The world has become a lot more
complicated.
Many of you may be using
third-party libraries which are
built on that Sockets
foundation.
Many more of you may be using
URLSession.
And you may have assumed that
URLSession is also just a wrap
around Sockets.
Well, not quite.
URLSession is actually built
using Apple's user space
networking code network
framework.
And starting now, in iOS 12, we
are exposing that same API that
URLSession uses so that your
apps can directly use that for
making TCP connections and other
appropriate use cases.
If you're doing things with URLs
and HTTP GETs, URLSession is
still your API of choice.
But for the things URLSession
doesn't cover, we now expose
network framework so your apps
can use that directly.
And if you're the developer of
one of these third-party
libraries, which are very
popular that are built on BSD
Sockets, we encourage you to
look at the network framework
APIs.
Move your library over to these
improved high-performance APIs,
and give us feedback about how
that goes for you.
So to summarize, we really
strongly recommend here and now
in 2018 that you avoid using BSD
Sockets.
Avoid using libraries that are
nothing but wrappers around BSD
Sockets.
And if you are one of the
authors of those libraries using
these older APIs, look at
switching over.
Come and meet us in the labs
this afternoon and tomorrow and
give us your feedback about what
it takes to move your libraries
to new APIs.
And with that, I would like to
invite my colleagues Jiten to
come up on stage and give you
more details about URLSession.
[ Applause ]
>> Thank you, Stuart.
Good morning everyone.
My name is Jiten Mehta.
And I'm an engineer on the CF
network team.
Today I'll be talking to you
about some networking best
practices for your apps.
Networking is an essential part
of every application.
Each year, you guys do a great
job of adding awesome features
to your apps.
And today I'll be talking to you
about some simple networking
details, details that can help
make your apps successful.
Our agenda for today is going to
cover four categories: reducing
latency, maximizing throughput,
increasing responsiveness, and
making better use of system
resources.
Before that, let's quickly
review URLSession, the API
you've been using.
URLSession is the recommended
high-level networking API
available on all Apple
platforms.
URLSession has first-class
support for HTTP/2 and HTTP/1.1.
If your app does not use HTTP,
we have support for
URLSessionStreamTask, an API
that allows you to make secure
TCP connections to a server over
which you can build your
arbitrary protocol.
That's URLSession.
Let's move on to our first
agenda item: reducing latency.
Let's suppose you and your
friends go to a restaurant where
the waiter walks up to you and
you say, "Can I get a glass of
water please?"
The waiter say, "Sure," walks
away, fetches you a glass of
water.
Your friend then says, "Can I
get a glass of water too?"
The waiter says, "Sure," walks
away, and fetches your friend a
glass of water.
Wouldn't it be faster if the
waiter took everyone's order at
the same time and reduce the
number of round trips?
The idea to reduce latency is
simple.
To reduce the number of back and
forths when you fetch a
resource.
Let's see how your apps can do
this.
First, let's look at some issues
with HTTP/1.1.
Your app wants to fetch a
resource, you can create a
URLSession task and call resume.
URLSession will create a new
connection for you, which
involves DNS, TCP and TLS.
Once the connection to the
server is established, we will
send out your request.
We will then wait to get a
response from the server.
This is the network idle time
when your app is not doing any
kind of networking, waiting to
get a response from the server.
Once we get a response, we will
call your completion block or
message your delegate indicating
that the load has finished.
Let's suppose in the middle of
this load your app wants to
fetch another resource from the
same server.
You can create another
URLSession task called resume
and URLSession will create a new
connection to fetch this
resource since it does not have
an idle connection in its
connection pool.
If your app wants to fetch yet
another resource from the same
server, you can create another
URLSession task and call resume
and we will create another
connection to fetch the
resource.
In this example, I've shown you
that we've created three
different connections to fetch
these resources from the same
server.
If you notice, we've spent a lot
of time opening new connections.
Let's see how this would look
like if you used a single
connection instead.
This is a single connection
case.
We saved a lot of time by not
opening new connections, but
there is another problem here.
The request number two which is
the green request has to wait
until response number one is
fully received.
The same problem applies to
request number three which is
the orange request which has to
wait until response number two
is fully received.
This problem is known as HTTP
head-of-line blocking.
Consider moving to HTTP/2.
HTTP/2 uses a single connection,
and it also solves the HTTP
head-of-line blocking problem.
HTTP/2 multiplexes multiple
streams over a single connection
allowing you to receive parallel
responses in an [inaudible]
fashion.
Let's analyze this example a
little more to see how HTTP/2
performs better than HTTP/1.1.
Pay attention to the times when
your app wants to fetch a
resource and the time when the
request is sent out.
In the HTTP/1.1 case, there is a
significant delay between the
time when your app desires a
resource and the time the
request is sent out.
HTTP/2 can significantly reduce
this delay and allows us to send
the request almost immediately
when the app desires the
resource.
Also pay attention to these gray
boxes.
If you recall, this is the
network idle time when your app
is not doing any networking,
waiting to get a response from
the server.
HTTP/2 can significantly reduce
this network idle time allowing
you to better utilize the
bandwidth and load the resources
much faster.
We just discussed many benefits
of using HTTP/2 over HTTP/1.1,
but let's quickly summarize
them.
HTTP/2 solves the head-of-line
blocking problem at the HTTP
layer.
And it also allows you to better
utilize the bandwidth.
If your apps use URLSession, you
don't need to make any
client-side changes.
Simply enable HTTP/2 on your
servers and you will see these
benefits.
By adopting HTTP/2, you can also
get some server-side savings
because devices running your
apps will now make fewer
connections to the servers.
This year, we have something new
in URLSession that is going to
add to the advantages of HTTP/2.
Introducing HTTP/2 Connection
Coalescing for URLSession.
HTTP/2 Connection Coalescing is
going to increase connection to
use even more.
Since your apps are not going to
be opening new connections, they
will become more responsive to
your users.
Starting with the [inaudible],
HTTP/2 Connection Coalescing is
going to be automatically done
on for all your apps using
URLSession.
Now let's see how Connection
Coalescing decides to reuse
connections.
Let's suppose you have an app
and that app wants to fetch a
resource from menu.example.com.
We open a connection with the
server, and the server presents
us with the certificate.
If your app wants to fetch
another resource from
delivery.example.com, we open
another connection and the
server presents us with another
certificate.
This is the old behavior where
URLSession would create two
connections to fetch these
resources from the given host
names.
But if you look closely, the
first certificate presented to
us covers all the subdomains
under example.com which means
delivery.example.com is covered
by this first certificate.
Also notice that
delivery.example.com, it results
to the same IP address as the
first connection.
At this point, it's safe for us
to assume we're talking to the
same endpoint and reuse the
connection instead of opening a
new one when we want to fetch
the second resource.
This saves us time by not
opening a new connection and
makes the load much faster.
HTTP/2 [inaudible] HTTP/2
Connection Coalescing new in iOS
12 and macOS Mojave.
Now let's see how using fewer
URLSession objects can help
reduce latency.
All the benefits of connections
we use that we just discussed in
the previous slides are
applicable only if you use the
same URLSession object to create
your tasks.
It's also important to know that
every URLSession object has a
connection pool and when you
create multiple of these
URLSession objects, you don't
get any benefit of connection to
use.
It's also important to note that
the URLSession objects are
fairly expensive to create and
have a non-trivial memory
footprint.
As we have in the past, we
continue to advise you to use
fewer URLSession objects.
Let's move on to our next topic
for the day: maximizing
throughput.
Coming back to our restaurant
example.
The waiter checks up on you and
you say, "Can I get an order of
grilled chicken tossed in creamy
tomato onion gravy made with a
lot of butter?"
Now that's a mouthful.
Wouldn't it be easier if you
just said, "Can I get butter
chicken?"
The idea to maximize throughput
is the same where you reduce the
number of bytes that you
transmit when you want to fetch
a resource.
Let's see how your apps can do
this.
Let's look at a couple of ways
to reduce the request size.
Pay attention to HTTP cookies.
They are not free and have a
non-trivial cost in storing and
looking them up.
Cookies are attached to all the
requests that match the domain
and path attribute.
And it can quickly increase your
request size.
Please use the domain and path
attribute wisely to make sure
cookies required by the servers
are attached to your requests.
Use of smaller cookies when
possible, and delete these
cookies when you no longer need
them.
Try to save some state on the
server so you can reduce the
number of client-side cookies.
Also consider moving to HTTP/2
to get benefits of header
compression.
Let's talk a little more about
compression.
HTTP compression, also known as
content and coding, is simply
compressing the data that is
shuttled between the client and
the server.
This allows us to better utilize
the bandwidth.
The algorithms that URLSession
supports and recommends are Gzip
and Brotli.
Gzip is widely supported and is
relatively fast.
Brotli support was introduced
last year in iOS 11 and macOS
High Sierra.
Brotli is optimized for
structured text and HTML.
And it has the best compression
ratio on short data.
Please enable compression on
your servers if you haven't done
so already.
Let's move on to our next topic
for the day: increasing
responsiveness.
Coming back to our restaurant
example.
Here you are here in San Jose
for WWDC, and you decide to meet
up with some old friends.
You and your friends are sitting
at the restaurant table.
Your drinks are here, but you
would like some more time to
catch up with your friends
before the food comes out.
You can simply tell the waiter,
"Can you please bring out our
food after some time?
We are in no rush."
The same concept can be applied
to responsiveness where you mark
your tasks with priority
depending on the other tasks
that you're doing.
Let's see how your apps can
benefit from this.
You might be familiar with these
five QoS classes associated with
dispatch queues and NSOperation
objects.
Data [inaudible] the CPU
scheduling policy.
URLSession is QoS-aware which
means it will capture the QoS
off the queue on which you call
task.resume.
And all the messages that it
sends to your delegates will
respect this QoS.
Let's take an example.
If your app wants to fetch some
data which is not time critical,
consider resuming that task on a
queue which has background QoS
to make sure this task does not
contend for CPU with other
higher priority work that your
app might be doing.
Network service type is the
property on the URLSession
configuration object that allows
you to classify your network
traffic that helps the system
prioritize the data leaving the
device.
This year, we have a new network
service type, the
responsiveData.
ResponsiveData is slightly
higher than the default type but
should be used judiciously.
An example where you might want
to use responsiveData is if you
have a shopping app and you are
on the checkout page.
You might want to mark your
payment request with the
responsiveData to make sure you
get a good response from the
server.
Traffic marked with the network
service type property will
maintain this tag across all the
hops when on a Cisco Fast Lane
network.
For more information on this
API, please view the WWDC
session from the year 2016.
Last year, we introduced the
URLSession Adaptable
Connectivity API
waitsForConnectivity.
waitsForConnectivity will simply
wait instead of failing the load
when your task does not have
connectivity.
In the past, you've been using
STNeworkReachability to do a
preflight check before you send
out your request.
But as Stuart pointed out a few
slides ago, there is a race
condition where the system might
tell you that you have
connectivity to a server but by
the time you create and send
your request, you've lost your
chance and you're no longer
connected to the server.
We recommend using
waitsForConnectivity which will
simply send out your request as
soon as a connection to the
server is available.
Optionally, you can implement
the taskIsWaitigForConnectivity
delegate method which gets
called when your task does not
have connectivity.
This can be helpful to present
the user with a different flow
or an offline UI for better user
experience.
For more information on this
API, please view the WWDC
session from last year where
this API was introduced.
Now let's move on to our last
topic for the day: making better
use of system resources.
Coming back to our restaurant
example.
You like the food at this place
so much that you decide to come
here for dinner the next day.
The restaurant has a delivery
service where you can place your
order today and they will
deliver the food to your house
the next day.
This not only saves you the time
and effort to go and pick up
your food but it also helps the
restaurant prioritize their work
based on your deadline.
Let's see how your apps can make
better use of system resources
to be more efficient.
Background sessions have upload
and download tasks.
These tasks use system
intelligence to decide when to
start and when to stop a
download based on various
factors like battery, CPU,
Wi-Fi, etcetera.
If your app wants to fetch a
large file, consider using
background sessions.
These tasks run out of process
which means your download will
continue even when your app is
in a suspended state.
For more information on
background sessions, please view
the WWDC session from the year
2014.
Caching is a great way of
reducing latency but it's
important to note that caching
might result in disk IO.
In the real world, we've seen
some apps write several
gigabytes of data to disk each
day which can cause severe flash
storage degradation.
Please don't cache unique
content.
Let's take an example.
Let's suppose you have an app, a
dating app, and you are
responsible for the networking
code of the app.
This app loads user profiles
with high-resolution images.
It might be wasteful to cache
these high-resolution images
because the user might swipe
left, move on to the next
profile, which means that the
images that you just cached are
probably not going to be
requested again.
Please consider making
client-side changes by adopting
the willChacheResponse delegate
method to decide what resources
should be cached.
If you own the servers, please
consider using cache control
headers to decide what resources
should be cacheable.
Let's quickly go over some of
the key points that we discussed
today.
Number one, order all your food
at the same time when you go to
a restaurant.
I'm just kidding.
Move to HTTP/2 today to get wins
like header compression,
connection coalescing and no
head-of-line blocking.
Use fewer URLSession objects to
reduce latency by reusing
connections.
This also reduces the memory
footprint so it's better use of
system resources.
Reduce the request size to
maximize throughput.
Pay attention to QoS to increase
the responsiveness of your apps.
And finally use background
sessions when you can to make
better use of system resources.
For more information on this
session, please visit this
website.
Now we'll have a short break.
And after the break, we'll
introduce you to network
framework, a modern alternative
to Sockets.
I would love to see you all at
the networking labs which are
going to be held today and
tomorrow.
Thank you all for being here.
And I hope everyone has a great
rest of the conference.
[ Applause ]