Slide 1

Slide 1 text

HTTP Can we do better?

Slide 2

Slide 2 text

How much does your application weigh?

Slide 3

Slide 3 text

Services

Slide 4

Slide 4 text

Services

Slide 5

Slide 5 text

Discovery ● Overlay Networks ● Registry/Reverse Proxying ● Port Scanning ● DNS

Slide 6

Slide 6 text

Discovery: Overlay Networks ● Slow ● Rather call it host/container discovery? ● Probably use Docker - Swarm

Slide 7

Slide 7 text

Discovery: Registry ● Etcd, consul, zookeeper ● Oh no, another cluster?

Slide 8

Slide 8 text

● How do you add dynamic hosts? ● Proxy could Crash? ● How to find Proxies? ● Connection Draining ● Latency+ ● Gateway Partitioning Discovery: Reverse Proxies

Slide 9

Slide 9 text

Discovery: DNS Based ● No Port based Information ● SRV is cool ○ No one uses it ● Some Languages don’t obey TTL. ● Health-check remains external process.

Slide 10

Slide 10 text

Components of Discovery ● Registry ○ Dynamically Configurable ● Registration ○ Clients emit Events ○ Registrar’s sees lack of events ● Health Check ○ Reachability ○ Load ○ Latency ● Load Balancing ○ Client side ○ Server Side

Slide 11

Slide 11 text

● Server - Side ○ Proxy ○ Haproxy, httpd, consul, nginx etc. ○ ALB, ELB ● Client - Side ○ Netflix OSS ● Algorithm ● Staleness Load Balancing ○ Round Robin ○ Weighted Round-Robin ○ Random ○ URL ○ Least Connections ○ Least Traffic ○ Least Latency ○ Recently Used.

Slide 12

Slide 12 text

Other Essentials ● Request Tracing ● Unified Logging ● Error Reporting ● Wildcard ● HTTP Multicast, Broadcast?

Slide 13

Slide 13 text

Alternate?

Slide 14

Slide 14 text

Sample Service

Slide 15

Slide 15 text

HTTP Way

Slide 16

Slide 16 text

PubSub/Redis

Slide 17

Slide 17 text

PubSub Way

Slide 18

Slide 18 text

Gilmour-Libs /gilmour-libs

Slide 19

Slide 19 text

Service Responder func bindListeners(g *G.Gilmour) { opts := G.NewHandlerOpts() g.ReplyTo("action.login", echoReply, opts) } func main() { engine := G.Get(redis.MakeRedis("127.0.0.1:6379", "")) bindListeners(engine) engine.Start() }

Slide 20

Slide 20 text

Service Caller func echoRequest(engine *G.Gilmour, msg string) (string, error) { req := engine.NewRequest("action.login") resp, err := req.Execute(G.NewMessage().SetData(msg)) if err != nil { return "", err } var output string err := resp.Next().GetData(&output) if err != nil { return "", err } return output, nil }

Slide 21

Slide 21 text

Request Response CALLER SERVICE HELLO? ALOHA! WRONG NUMBER SENDER_ID CODE

Slide 22

Slide 22 text

No/Good Service Discovery ● No querying discovery process ● Call service and not servers

Slide 23

Slide 23 text

Load Balancing

Slide 24

Slide 24 text

Load Balancing - Then NOTIFICATION SERVER 1 REPLICATED LOAD BALANCER X.Y.Y.Z ? CALLER SERVICE REGISTER I, AM HEALTHY? NOTIFICATION SERVER 2 NOTIFICATION SERVER 3

Slide 25

Slide 25 text

Load Balancing : Now NOTIFICATION SERVER 2 GILMOUR MANAGER.NOTIFICATION NOTIFICATION SERVER 1 NOTIFICATION SERVER 3 MANAGER.NOTIFICATION MANAGER.NOTIFICATION CALLER SERVICE MANAGER.NOTIFICATION {“NOTIFICATION”: “DATA”}

Slide 26

Slide 26 text

No/Good Load Balancing ● Has Capacity, Will Serve ● Message delivered to one and all ● Fittest node acquires lock first ● No need for Connection draining

Slide 27

Slide 27 text

And, How?

Slide 28

Slide 28 text

Just this func bindListeners(g *G.Gilmour) { opts := G.NewHandlerOpts().SetGroup("exclusive") g.ReplyTo("echo", echoReply, opts) }

Slide 29

Slide 29 text

Tracing, much?

Slide 30

Slide 30 text

$: redis-cli MONITOR 1509330865.376313 [0 127.0.0.1:59770] "PUBSUB" "NUMSUB" "gilmour.request.echo" 1509330865.376388 [0 127.0.0.1:59768] "SUBSCRIBE" "gilmour.response.1643e3fc-6362-4a2d-853b-35e8447a63f2" 1509330865.376502 [0 127.0.0.1:59770] "PUBLISH" "gilmour.request.echo" "{\"data\":\"Hello: World\",\"code\":200,\"sender\":\"1643e3fc-6362-4a2d-853b-35e8447a63f2\"}" 1509330865.376764 [0 127.0.0.1:59718] "SET" "1643e3fc-6362-4a2d-853b-35e8447a63f2exclusive" "1643e3fc-6362-4a2d-853b-35e8447a63f2exclusive" "NX" "EX" "600" 1509330865.376928 [0 127.0.0.1:59718] "PUBLISH" "gilmour.response.1643e3fc-6362-4a2d-853b-35e8447a63f2" "{\"data\":\"Pong Hello: World\",\"code\":200,\"sender\":\"gilmour.response.1643e3fc-6362-4a2d-853b-35e8447a63f2\"}" 1509330865.377133 [0 127.0.0.1:59768] "UNSUBSCRIBE" "gilmour.response.1643e3fc-6362-4a2d-853b-35e8447a63f2"

Slide 31

Slide 31 text

Network practices, much?

Slide 32

Slide 32 text

How? # Server Side Timeouts opts := G.NewHandlerOpts().SetTimeout(500) g.ReplyTo("echo", echoReply, opts) # Client Side Timeouts opts := G.NewRequestOpts().SetTimeout(400) req := engine.NewRequestWithOpts("action.login", opts)

Slide 33

Slide 33 text

Logging

Slide 34

Slide 34 text

How? G.Logf("action.login %v", "message") G.Log("action.login")

Slide 35

Slide 35 text

Errors

Slide 36

Slide 36 text

What do you do with Errors ● Status Code >= 300 is reported. ● Policy can be: ○ Publish ○ Queue ○ Ignore func (r *Redis) SetErrorPolicy(policy string) error { if policy != errorPolicyQueue && policy != errorPolicyPublish && policy != errorPolicyIgnore { return errors.New("Invalid policy")) } r.errorPolicy = policy return nil }

Slide 37

Slide 37 text

Error Sample

Slide 38

Slide 38 text

Asynchronous Architectures

Slide 39

Slide 39 text

HTTP won’t, but ● Queues ● Celery ● SideKiq ● Kafka ● SQS ● Pravega ● Nats … Can

Slide 40

Slide 40 text

Asynchronous EVENT.POWER_UP EVENT.* EVENT.* GROUP: REVENUE FP SCALING PUSH MESSAGE SERVER ADS/MARKETINGS ERVER UNLOCK LEVEL BADGE SERVICE EVENT.* ADS/ MARKETING GAME GILMOUR (Redis PubSub) EVENT EVENT.BRIDGE_FALL FALL FROM BRIDGE FALL FROM BRIDGE FALL FROM BRIDGE GROUP: BRIDGE_FALL

Slide 41

Slide 41 text

Logging, Revisited

Slide 42

Slide 42 text

Service Responder func bindListeners(g *G.Gilmour) { opts := G.NewHandlerOpts() g.Slot("example.log", func(req *G.Request) { var msg string if err := req.Data(&msg); err == nil { log.Println(req.Sender(), "->", msg) } }, nil) }

Slide 43

Slide 43 text

Asynchronous Caller func sendLog(engine *G.Gilmour) { line := "WordCount" engine.Signal("example.log", G.NewMessage().SetData(line)) line := "Fetching Data" // err will be not nil, if Message for example.log was not received by anyone. _, err := engine.Signal("example.log", G.NewMessage().SetData(line)) }

Slide 44

Slide 44 text

Composition

Slide 45

Slide 45 text

● compose - service1 | service2 | composition3 ● andand - service1 && service2 && composition3 ● oror - service1 || composition2 || service3 ● batch ○ (service1; service2; service3) > out ○ service1; composition2; service3 > out ● parallel ● lambda functions

Slide 46

Slide 46 text

Composition pipe := engine.NewPipe( engine.NewRequest("example.fetch"), engine.NewRequest("example.words"), engine.NewRequest("example.stopfilter"), engine.NewRequest("example.count"), engine.NewParallel( engine.NewRequest("example.popular3"), engine.NewRequest("example.popular4"), engine.NewRequest("example.popular5"), ), ) resp, err := pipe.Execute(G.NewMessage().SetData(url)) expected := []string{} err := resp.Next().GetData(&expected)

Slide 47

Slide 47 text

Composition batch := e.NewPipe( e.NewRequest("weather.fetch"), e.NewRequest("weather.group"), e.NewParallel( e.NewPipe( e.NewParallel( e.NewRequest("weather.min"), e.NewRequest("weather.max"), )), e.NewPipe( e.NewParallel( e.NewRequest("weather.min"), e.NewRequest("weather.max"), )))) resp, _ := batch.Execute(G.NewMessage().SetData("pune"))

Slide 48

Slide 48 text

Demo

Slide 49

Slide 49 text

Examples: Composition

Slide 50

Slide 50 text

Thank you! Piyush Verma @meson10 Oogway Consulting http://oogway.in