CocoaConf: The Language of Mobile Software is APIs
-
Upload
tim-burks -
Category
Technology
-
view
328 -
download
2
Transcript of CocoaConf: The Language of Mobile Software is APIs
I was an “indie” iOS developer
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...
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.”
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.
So let’s build everything with one language!
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
What does an OpenAPI spec look like?
Documentation Generation
Code Generation
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
}
The Protocol Buffer Language
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
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
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
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
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
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
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
}
We’re building Swift support for gRPC.
We are working to add Protocol Buffers and gRPC to OpenAPI.
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
You can run Swift on Google Cloud Platform right now.
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
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