$30 off During Our Annual Pro Sale. View Details »

HTTP: Can we do Better?

HTTP: Can we do Better?

How much does your application weigh when you build it using HTTP Constructs? Can you achieve the same availability and reliability using another alternatives?

Piyush Verma

November 13, 2017
Tweet

More Decks by Piyush Verma

Other Decks in Technology

Transcript

  1. HTTP
    Can we do better?

    View Slide

  2. How much does your application
    weigh?

    View Slide

  3. Services

    View Slide

  4. Services

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  9. 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.

    View Slide

  10. 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

    View Slide

  11. ● 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.

    View Slide

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

    View Slide

  13. Alternate?

    View Slide

  14. Sample Service

    View Slide

  15. HTTP Way

    View Slide

  16. PubSub/Redis

    View Slide

  17. PubSub Way

    View Slide

  18. Gilmour-Libs
    /gilmour-libs

    View Slide

  19. 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()
    }

    View Slide

  20. 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
    }

    View Slide

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

    View Slide

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

    View Slide

  23. Load Balancing

    View Slide

  24. 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

    View Slide

  25. 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”}

    View Slide

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

    View Slide

  27. And, How?

    View Slide

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

    View Slide

  29. Tracing, much?

    View Slide

  30. $: 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"

    View Slide

  31. Network practices, much?

    View Slide

  32. 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)

    View Slide

  33. Logging

    View Slide

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

    View Slide

  35. Errors

    View Slide

  36. 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
    }

    View Slide

  37. Error Sample

    View Slide

  38. Asynchronous Architectures

    View Slide

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

    View Slide

  40. 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

    View Slide

  41. Logging,
    Revisited

    View Slide

  42. 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)
    }

    View Slide

  43. 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))
    }

    View Slide

  44. Composition

    View Slide

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

    View Slide

  46. 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)

    View Slide

  47. 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"))

    View Slide

  48. Demo

    View Slide

  49. Examples: Composition

    View Slide

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

    View Slide