CocoaConf: The Language of Mobile Software is APIs

106
The Language of Mobile Software is APIs [email protected]

Transcript of CocoaConf: The Language of Mobile Software is APIs

The Language of Mobile Software is APIs

[email protected]

One OS (more or less) for all Apple devices.

Darwin Kernel, based on Mach, apps run in sandboxes.

Many platforms, both new (tvOS, watchOS) and old (macOS).

Apps are developed in Objective-C & Swift.

Life moves pretty fast:

Quick OS update cycle

Swift and APIs still changing

Apps are frequently distributed systems.

iOS developers know this...

10 Billion

API callsevery second

Will all the world’s computers be in data centers?

No way!(Lots of them will be on eBay)

What if we thought of those data centers as one computer?

At Google, we’re building an operating system for distributed computing...

1. Borg → Kubernetes

2. Stubby → gRPC

3. One Platform → Endpoints

But there’s this wall.

Conway’s Law: “organizations which design systems... are constrained to produce

designs which are copies of the communication structures of these organizations.”

Swift can help us

tear down that wall.

Are iOS developers ready for this?

We are used to change.

iOS 10 adoption is high.

Swift has iterated rapidly.

We’ve been burned by BaaS.

Proprietary Parse and StackMob were shut down.

Open Source Apache Usergrid hasn’t particularly taken off.

Sorry, all developers don’t write with the same language or on the same OS.

APIsare how we connect the parts of our distributed systems, and they work pretty well.

Standardized description of REST APIs

Documentation generation

Code generation

API service configuration

API authoring and creation

OpenAPI is focused on REST APIs

What’s not-so-great about REST?

Resources don’t always map well to URI paths.

Actions don’t always map well to HTTP verbs.

REST APIs are stateless, so multi-step transactions are more difficult with state

carried in “back doors” like headers or query parameters.

REST APIs don’t support streaming.

Most REST payloads and architectures are expensive at large scale.

gRPC enables remote procedure calls with streaming:

send a protocol buffer, get a protocol buffer

send a protocol buffer, get a stream of protocol buffers

send a stream of protocol buffers, get a protocol buffer

send a stream of protocol buffers, get a stream of protocol buffers

Not limited to protocol buffers, but with built-in support for them.

Protocol buffers are a language-neutral, platform-neutral, extensible mechanism

for serializing structured data.

Implemented in many languages, sometimes many times...

“Protocol Buffers” means several things

1. A serialization mechanism

2. An interface description language

3. A methodology

Protocol Buffer Serialization

It’s just a stream of bytes

[field_number<<3 + wire_type] [length if necessary] [data]...

$ hexdump /tmp/request.bin

0000000 0a 05 68 65 6c 6c 6f

0a is “0000 1010”, sofield_number = 1

wire_type = 2

public enum FieldType: Int {

case double = 1

case float = 2

case int64 = 3

case uint64 = 4

case int32 = 5

case fixed64 = 6

case fixed32 = 7

case bool = 8

case string = 9

case group = 10

case message = 11

case bytes = 12

case uint32 = 13

case enumeration = 14

case sfixed32 = 15

case sfixed64 = 16

case sint32 = 17 // ZigZag encoded

case sint64 = 18 // ZigZag encoded

}

public enum WireType: Int {

case varint = 0

case fixed64 = 1

case lengthDelimited = 2

case startGroup = 3

case endGroup = 4

case fixed32 = 5

}

Q. How do we know the field type?

echo.proto

syntax = "proto3";

package echo;

service Echo {

rpc Get(EchoRequest) returns (EchoResponse) {}

rpc Update(stream EchoRequest) returns (stream EchoResponse) {}

}

message EchoRequest {

string text = 1;

}

message EchoResponse {

string text = 1;

}

The Protocol Buffer methodology

$ protoc echo.proto -o echo.out --go_out=.

$ which protoc-gen-go

../bin/protoc-gen-go

$ more echo.pb.go

// Code generated by protoc-gen-go.

// source: echo.proto

// DO NOT EDIT!

...

Interface Builder

Visual designer

Saves coding

Builds on message sending

conventions of Objective-C.

It isn’t exactly a code

generator...

but it is a lot like a code

generator.

Protocol Buffers is Interface Builder for Data.

Interface Builder: Developers specify

their interfaces using a special tool,

tooling compiles and integrates that into

their apps.

Protocol Buffers: Developers specify

their data structures using a special

language, tooling compiles and

integrates that into their apps.

message Person {

string name = 1;

int32 id = 2;

string email = 3;

enum PhoneType {

MOBILE = 0;

HOME = 1;

WORK = 2;

}

message PhoneNumber {

string number = 1;

PhoneType type = 2;

}

repeated PhoneNumber phone = 4;

}

How to use Apple’s Swift Protocol Buffer Library

What is gRPC ?

A remote procedure call (RPC) framework layered on HTTP/2

Enables client and server applications to communicate transparently

Client “calls” methods on a Server (which may be on a different machine) as if it

were a local service

Makes it easy to build heterogeneous distributed systems

Separate full implementations in C, Java, and Go.

C-based support for C++, Python, Node.js, Ruby, PHP, C#, Objective-C, ...

What is gRPC ?

Google Cloud Platform

Interoperability

Java Service

Python Service

GoLang Service

C++ Service

gRPC Service

gRPC Stub

gRPC Stub

gRPC Stub

gRPC Stub

gRPC Service

gRPC Service

gRPC Service

gRPC Stub

Google Cloud Platform

Google Cloud Platform

First Law of Distributed Object Design: don't distribute your objects.

Martin Fowler

http://martinfowler.com/articles/distributed-objects-microservices.html

“ ”

Google Cloud Platform

The Fallacies of Distributed Computing

The network is reliable

Latency is zero

Bandwidth is infinite

The network is secure

https://blogs.oracle.com/jag/resource/Fallacies.html

Topology doesn't change

There is one administrator

Transport cost is zero

The network is homogeneous

Google Cloud PlatformGoogle Cloud Platform

Services not Objects, Messages not References.

Promote the microservices design philosophy of coarse-grained message exchange between systems while avoiding the pitfalls of distributed objects and the fallacies of ignoring the network.

gRPC Principles & Requirements

http://www.grpc.io/blog/principles

Google Cloud Platform 67

First-class feature in gRPC.

Deadline is an absolute point in time.

Deadline indicates to the server how

long the client is willing to wait for an

answer.

RPC will fail with DEADLINE_EXCEEDED

status code when deadline reached.

gRPC Deadlines

Google Cloud Platform

Timeouts?

GW

A1 A2 A3

B1 B2 B3

C1 C2 C3

200 ms

?

?

?

? ?

? ?

? ?

Google Cloud Platform

Timeout Propagation

Gateway

90 ms

timeout =200 - 40

ms

timeout =160 - 90 - 20

ms

timeout = 200 ms

40 ms

20 ms

20 ms 60 ms

timeout reached!

230 ms

Google Cloud Platform

gRPC Deadline Propagation

Gateway

90 ms

Now = 1476600000000

Deadline = 1476600000200

40 ms

20 ms

20 ms 60 ms

withDeadlineAfter(200, MILLISECONDS)

Now = 1476600000040

Deadline = 1476600000200

Now = 1476600000150

Deadline = 1476600000200

Now = 1476600000230

Deadline = 1476600000200

DEADLINE_EXCEEDED DEADLINE_EXCEEDED DEADLINE_EXCEEDED DEADLINE_EXCEEDED

Google Cloud Platform

Timeouts?

GW

A1 A2 A3

B1 B2 B3

C1 C2 C3

200 ms

?

?

?

? ?

? ?

? ?

Google Cloud Platform

Timeouts for Real World?

GW

A1 A2 A3

B1 B2 B3

C1 C2 C3

200 ms

gRPC use cases

Client-server communication

Access Google Cloud Services

Build distributed applications

• In data-centers

• In public/private cloud

• Clients and servers across:

• Mobile

• Web

• Cloud• Also

• Embedded systems, IoT

• From GCP

• From Android and iOS devices

• From everywhere else

Unary API:

Client sends a request, server sends a response

Streaming APIs:

Multiple messages back and forth between Client and Server within the same call.

Three types of streaming APIs

Client Streaming API

Server Streaming API

Bi-directional Streaming API

gRPC API Styles

Unary API

syntax = “proto3”;

message HelloRequest {string name = 1;

}

message HelloReply {string message = 1;

}

service HelloService {rpc SayHello(HelloRequest) returns (HelloReply);

}

Unary API: Client sends a

request, server sends a

response

Streaming APIs - 1 (of 3) Client Streaming

syntax = “proto3”;

message Latency {string name = 1;double val = 2;

}

message Histogram {string name = 1double p99 = 2;double p999 = 3;double avg = 4;

}

service MetricsService {rpc ReportLateny(stream Latency) returns Histogram;

}

Client Streaming API: Client

sends multiple messages;

Server sends one response

(Note: Server may choose to send the response

before all the client messages are received)

Streaming APIs - 2 (of 3) Server Streaming

syntax = “proto3”;

message StockRequest {string stocksymbol = 1;

}

message StockResponse {double price = 1;

}

service StockTickerService {rpc GetTicker(StockRequest) returns (stream StockResponse);

}

Server Streaming API: Client

sends one message; Server

sends multiple messages

Streaming APIs - 3 (of 3) Bidirectional Streaming

syntax = “proto3”;

message ChatMessage {string msg = 1;

}

service ChatService {rpc Chat(stream ChatMessage) returns (stream ChatMessage);

}

Bidi Streaming API: Client and

Server can send multiple

messages to each other

(Note: Client and server can independently send

messages to each other i.e they do not have to wait

for receiving a client message before sending a

message)

Google Cloud Platform

gRPC vs JSON/HTTP for Google Cloud Pub/Sub

Publishing 50KB messages at

maximum throughput from a

single n1-highcpu-16 GPE VM

instance, using 9 gRPC channels.

More impressive than the

almost 3x increase in

throughput, is that it took only

1/4 of the CPU resources.

11x difference per CPU3x increase in throughput

https://cloud.google.com/blog/big-data/2016/03/announcing-grpc-alpha-for-google-cloud-pubsub

Google Cloud Platform

gRPC API in Google Cloud

A massively scalable

NoSQL database

service.

A fully-managed real-

time messaging

service.

Speech to text

conversion powered

by machine learning.

Cloud Speech APICloud Bigtable Cloud PubSub

Google Cloud Platform

Some gRPC Adopters

Google Cloud Platform

Netflix deprecated its RPC framework in favor of gRPC:

“Our team has instead building an RPC solution on top of gRPC. We are doing this transition for two main reasons: multi-language support and better extensibility/composability through request interceptors. That’s our current plan moving forward.”

https://github.com/Netflix/ribbon

gRPC Adopters

got code?

echo.proto

syntax = "proto3";

package echo;

service Echo {

rpc Get(EchoRequest) returns (EchoResponse) {}

rpc Update(stream EchoRequest) returns (stream EchoResponse) {}

}

message EchoRequest {

string text = 1;

}

message EchoResponse {

string text = 1;

}

echo.pb.go (generated messsages)

package echo

...

type EchoRequest struct {

Text string `protobuf:"bytes,1,opt,name=text" json:"text,omitempty"`

}

func (m *EchoRequest) Reset() { *m = EchoRequest{} }

func (m *EchoRequest) String() string { return proto.CompactTextString(m) }

func (*EchoRequest) ProtoMessage() {}

func (*EchoRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }

type EchoResponse struct {

Text string `protobuf:"bytes,1,opt,name=text" json:"text,omitempty"`

}

func (m *EchoResponse) Reset() { *m = EchoResponse{} }

func (m *EchoResponse) String() string { return proto.CompactTextString(m) }

func (*EchoResponse) ProtoMessage() {}

func (*EchoResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }

echo.pb.go (generated client support)

// Client API for Echo service

type EchoClient interface {

Get(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error)

Update(ctx context.Context, opts ...grpc.CallOption) (Echo_UpdateClient, error)

}

type echoClient struct {

cc *grpc.ClientConn

}

func NewEchoClient(cc *grpc.ClientConn) EchoClient {

return &echoClient{cc}

}

func (c *echoClient) Get(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error) {

out := new(EchoResponse)

err := grpc.Invoke(ctx, "/echo.Echo/Get", in, out, c.cc, opts...)

if err != nil {

return nil, err

}

return out, nil

}

func (c *echoClient) Update(ctx context.Context, opts ...grpc.CallOption) (Echo_UpdateClient, error) {

stream, err := grpc.NewClientStream(ctx, &_Echo_serviceDesc.Streams[0], c.cc, "/echo.Echo/Update", opts...)

client.go (hand-written)

// Set up a connection to the server.

var conn *grpc.ClientConn

var err error

if !*useTLS {

if *address == "" {

*address = "localhost:8080"

}

conn, err = grpc.Dial(*address, grpc.WithInsecure())

} else {

if *address == "" {

*address = "localhost:443"

}

conn, err = grpc.Dial(*address,

grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{

// remove the following line if the server certificate is signed by a certificate

authority

InsecureSkipVerify: true,

})))

}

defer conn.Close()

c := pb.NewEchoClient(conn)

client.go (hand-written)

response, err := c.Get(context.Background(), &pb.EchoRequest{Text: message})

echo.pb.go (generated server support)

// Server API for Echo service

type EchoServer interface {

Get(context.Context, *EchoRequest) (*EchoResponse, error)

Update(Echo_UpdateServer) error

}

func RegisterEchoServer(s *grpc.Server, srv EchoServer) {

s.RegisterService(&_Echo_serviceDesc, srv)

}

func _Echo_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {

in := new(EchoRequest)

if err := dec(in); err != nil {

return nil, err

}

if interceptor == nil {

return srv.(EchoServer).Get(ctx, in)

}

info := &grpc.UnaryServerInfo{

Server: srv,

FullMethod: "/echo.Echo/Get",

}

handler := func(ctx context.Context, req interface{}) (interface{}, error) {

return srv.(EchoServer).Get(ctx, req.(*EchoRequest))

}

server.go (hand-written)func main() {

var useTLS = flag.Bool("tls", false, "Use tls for connections.")

flag.Parse()

var err error

var lis net.Listener

var grpcServer *grpc.Server

if !*useTLS {

lis, err = net.Listen("tcp", ":8080")

if err != nil {

log.Fatalf("failed to listen: %v", err)

}

grpcServer = grpc.NewServer()

} else {

certFile := "ssl.crt"

keyFile := "ssl.key"

creds, err := credentials.NewServerTLSFromFile(certFile, keyFile)

lis, err = net.Listen("tcp", ":443")

if err != nil {

log.Fatalf("failed to listen: %v", err)

}

grpcServer = grpc.NewServer(grpc.Creds(creds))

}

pb.RegisterEchoServer(grpcServer, &echoServer)

grpcServer.Serve(lis)

}

server.go (hand-written)

func (s *EchoServer)

Get(ctx context.Context, r *pb.EchoRequest) (*pb.EchoResponse, error) {

response := &pb.EchoResponse{}

response.Text = "Go nonstreaming echo " + r.Text

fmt.Printf("Get received: %s\n", r.Text)

return response, nil

}

What is Google doing?

We’re building Swift support for gRPC.

We’re embracing OpenAPI.

Publish OpenAPI specifications for all Google APIs

and engage with the community to

create and support open-source API services for clients and servers.

OpenAPI enables a “true” Interface Builder for APIs.

Replace protoc with an OpenAPI-based graphical API builder.

Have that builder implement protoc’s plugin architecture.

Use all the existing protoc plugins!

OpenAPI-based

graphical API editor

Java

C#

Python

Swift

PHP

C++

Ruby

Objective-C

protoc plugins

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

Proprietary + Confidential

● API Management from Google

● This architecture serves hundreds of

billions of requests per day

● All configuration happens through

Open API spec or via GRPC

Cloud Endpoints

What is API Management?

Key features

Across all use cases (public, private, mobile, microservice), 3 key needs:

Control access,

authenticate users

Logging and monitoring

of key metrics

Speed and scalability

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

Proprietary + Confidential

Dashboards and UI

Configuration (access, auth, etc) enforced at runtime

What does Google offer?

Your

Code

We’re hiring.

jobs.google.com