Skip to content

Commit

Permalink
Merge pull request #46 from ipfs/feat/improved-http-limits-and-dns-cache
Browse files Browse the repository at this point in the history
feat: improved http limits and dns cache
  • Loading branch information
lidel committed Feb 21, 2023
2 parents e4d22d2 + 9972ef2 commit 5393c4c
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 62 deletions.
59 changes: 2 additions & 57 deletions blockstore.go
Expand Up @@ -2,12 +2,8 @@ package main

import (
"context"
"crypto/tls"
"net/http"
"net/url"
"time"

"github.com/filecoin-saturn/caboose"
"github.com/ipfs/go-cid"
blockstore "github.com/ipfs/go-ipfs-blockstore"
exchange "github.com/ipfs/go-ipfs-exchange-interface"
Expand All @@ -17,8 +13,8 @@ import (

const GetBlockTimeout = time.Second * 60

func newExchange(orchestrator, loggingEndpoint string) (exchange.Interface, error) {
b, err := newCabooseBlockStore(orchestrator, loggingEndpoint)
func newExchange(orchestrator, loggingEndpoint string, cdns *cachedDNS) (exchange.Interface, error) {
b, err := newCabooseBlockStore(orchestrator, loggingEndpoint, cdns)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -65,54 +61,3 @@ func (e *exchangeBsWrapper) Close() error {
}

var _ exchange.Interface = (*exchangeBsWrapper)(nil)

func newCabooseBlockStore(orchestrator, loggingEndpoint string) (blockstore.Blockstore, error) {
var (
orchURL *url.URL
loggURL *url.URL
err error
)

if orchestrator != "" {
orchURL, err = url.Parse(orchestrator)
if err != nil {
return nil, err
}
}

if loggingEndpoint != "" {
loggURL, err = url.Parse(loggingEndpoint)
if err != nil {
return nil, err
}
}

saturnClient := &http.Client{
Timeout: caboose.DefaultSaturnRequestTimeout,
Transport: &withUserAgent{
RoundTripper: &http.Transport{
TLSClientConfig: &tls.Config{
ServerName: "strn.pl",
},
},
},
}

saturnServiceClient := &http.Client{
Timeout: caboose.DefaultSaturnRequestTimeout,
Transport: &withUserAgent{RoundTripper: http.DefaultTransport},
}

return caboose.NewCaboose(&caboose.Config{
OrchestratorEndpoint: orchURL,
OrchestratorClient: saturnServiceClient,

LoggingEndpoint: *loggURL,
LoggingClient: saturnServiceClient,
LoggingInterval: 5 * time.Second,

DoValidation: true,
PoolRefresh: 5 * time.Minute,
SaturnClient: saturnClient,
})
}
83 changes: 83 additions & 0 deletions blockstore_caboose.go
@@ -0,0 +1,83 @@
package main

import (
"crypto/tls"
"net/http"
"net/url"
"time"

"github.com/filecoin-saturn/caboose"
blockstore "github.com/ipfs/go-ipfs-blockstore"
)

func newCabooseBlockStore(orchestrator, loggingEndpoint string, cdns *cachedDNS) (blockstore.Blockstore, error) {
var (
orchURL *url.URL
loggURL *url.URL
err error
)

if orchestrator != "" {
orchURL, err = url.Parse(orchestrator)
if err != nil {
return nil, err
}
}

if loggingEndpoint != "" {
loggURL, err = url.Parse(loggingEndpoint)
if err != nil {
return nil, err
}
}

saturnServiceClient := &http.Client{
Timeout: caboose.DefaultSaturnRequestTimeout,
Transport: &withUserAgent{
RoundTripper: &http.Transport{
DialContext: cdns.dialWithCachedDNS,
},
},
}

saturnRetrievalClient := &http.Client{
Timeout: caboose.DefaultSaturnRequestTimeout,
Transport: &withUserAgent{
RoundTripper: &http.Transport{
// Increasing concurrency defaults from http.DefaultTransport
MaxIdleConns: 1000,
MaxConnsPerHost: 100,
MaxIdleConnsPerHost: 100,
IdleConnTimeout: 90 * time.Second,

DialContext: cdns.dialWithCachedDNS,

// Saturn Weltschmerz
TLSClientConfig: &tls.Config{
// Saturn use TLS in controversial ways, which sooner or
// later will force them to switch away to different domain
// name and certs, in which case they will break us. Since
// we are fetching raw blocks and dont really care about
// TLS cert being legitimate, let's disable verification
// to save CPU and to avoid catastrophic failure when
// Saturn L1s suddenly switch to certs with different DNS name.
InsecureSkipVerify: true,
// ServerName: "strn.pl",
},
},
},
}

return caboose.NewCaboose(&caboose.Config{
OrchestratorEndpoint: orchURL,
OrchestratorClient: saturnServiceClient,

LoggingEndpoint: *loggURL,
LoggingClient: saturnServiceClient,
LoggingInterval: 5 * time.Second,

DoValidation: true,
PoolRefresh: 5 * time.Minute,
SaturnClient: saturnRetrievalClient,
})
}
68 changes: 68 additions & 0 deletions dns_cache.go
@@ -0,0 +1,68 @@
package main

import (
"context"
"net"
"time"

"github.com/rs/dnscache"
)

// How often should we check for successful updates to cached entries
const dnsCacheRefreshInterval = 5 * time.Minute

// Local DNS cache because in this world things are ephemeral
type cachedDNS struct {
resolver *dnscache.Resolver
refresher *time.Ticker
}

func newCachedDNS(refreshInterval time.Duration) *cachedDNS {
cache := &cachedDNS{
resolver: &dnscache.Resolver{},
refresher: time.NewTicker(refreshInterval),
}

// Configure DNS cache to not remove stale records to protect gateway from
// catastrophic failures like https://github.com/ipfs/bifrost-gateway/issues/34
options := dnscache.ResolverRefreshOptions{}
options.ClearUnused = false
options.PersistOnFailure = true

// Every refreshInterval we check for updates, but if there is
// none, or if domain disappears, we keep the last cached version
go func(cdns *cachedDNS) {
defer cdns.refresher.Stop()
for range cdns.refresher.C {
cdns.resolver.RefreshWithOptions(options)
}
}(cache)

return cache
}

// dialWithCachedDNS implements DialContext that uses cachedDNS
func (cdns *cachedDNS) dialWithCachedDNS(ctx context.Context, network string, addr string) (conn net.Conn, err error) {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
ips, err := cdns.resolver.LookupHost(ctx, host)
if err != nil {
return nil, err
}
// Try all IPs returned by DNS
for _, ip := range ips {
var dialer net.Dialer
conn, err = dialer.DialContext(ctx, network, net.JoinHostPort(ip, port))
if err == nil {
break
}
}
return
}

func (cdns *cachedDNS) Close() error {
cdns.refresher.Stop()
return nil
}
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -26,6 +26,7 @@ require (
github.com/libp2p/go-libp2p v0.25.1
github.com/multiformats/go-multicodec v0.7.0
github.com/prometheus/client_golang v1.14.0
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417
github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.1
go.uber.org/atomic v1.10.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -932,6 +932,8 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 h1:Lt9DzQALzHoDwMBGJ6v8ObDPR0dzr2a6sXTB1Fq7IHs=
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
Expand Down
8 changes: 4 additions & 4 deletions handlers.go
Expand Up @@ -39,14 +39,14 @@ func withRequestLogger(next http.Handler) http.Handler {
})
}

func makeGatewayHandler(saturnOrchestrator, saturnLogger string, kuboRPC []string, port int, blockCacheSize int) (*http.Server, error) {
func makeGatewayHandler(saturnOrchestrator, saturnLogger string, kuboRPC []string, port int, blockCacheSize int, cdns *cachedDNS) (*http.Server, error) {
// Sets up an exchange based on using Saturn as block storage
exch, err := newExchange(saturnOrchestrator, saturnLogger)
exch, err := newExchange(saturnOrchestrator, saturnLogger, cdns)
if err != nil {
return nil, err
}

// Sets up an LRU cache to store blocks in
// Sets up a cache to store blocks in
cacheBlockStore, err := newCacheBlockStore(blockCacheSize)
if err != nil {
return nil, err
Expand All @@ -55,7 +55,7 @@ func makeGatewayHandler(saturnOrchestrator, saturnLogger string, kuboRPC []strin
// Set up support for identity hashes (https://github.com/ipfs/bifrost-gateway/issues/38)
cacheBlockStore = bstore.NewIdStore(cacheBlockStore)

// Sets up a blockservice which tries the LRU cache and falls back to the exchange
// Sets up a blockservice which tries the cache and falls back to the exchange
blockService := blockservice.New(cacheBlockStore, exch)

// Sets up the routing system, which will proxy the IPNS routing requests to the given gateway.
Expand Down
5 changes: 4 additions & 1 deletion main.go
Expand Up @@ -52,7 +52,10 @@ var rootCmd = &cobra.Command{

log.Printf("Starting %s %s", name, version)

gatewaySrv, err := makeGatewayHandler(saturnOrchestrator, saturnLogger, kuboRPC, gatewayPort, blockCacheSize)
cdns := newCachedDNS(dnsCacheRefreshInterval)
defer cdns.Close()

gatewaySrv, err := makeGatewayHandler(saturnOrchestrator, saturnLogger, kuboRPC, gatewayPort, blockCacheSize, cdns)
if err != nil {
return err
}
Expand Down

0 comments on commit 5393c4c

Please sign in to comment.