浏览代码

Merge pull request #36 from fastly/master

Performance enhancements
Brad Fitzpatrick 8 年之前
父节点
当前提交
1952afaa55
共有 3 个文件被更改,包括 74 次插入8 次删除
  1. 24 6
      memcache/memcache.go
  2. 33 0
      memcache/memcache_test.go
  3. 17 2
      memcache/selector.go

+ 24 - 6
memcache/memcache.go

@@ -64,14 +64,17 @@ var (
 	ErrNoServers = errors.New("memcache: no servers configured or available")
 )
 
-// DefaultTimeout is the default socket read/write timeout.
-const DefaultTimeout = 100 * time.Millisecond
-
 const (
-	buffered            = 8 // arbitrary buffered channel size, for readability
-	maxIdleConnsPerAddr = 2 // TODO(bradfitz): make this configurable?
+	// DefaultTimeout is the default socket read/write timeout.
+	DefaultTimeout = 100 * time.Millisecond
+
+	// DefaultMaxIdleConns is the default maximum number of idle connections
+	// kept for any single address.
+	DefaultMaxIdleConns = 2
 )
 
+const buffered = 8 // arbitrary buffered channel size, for readability
+
 // resumableError returns true if err is only a protocol-level cache error.
 // This is used to determine whether or not a server connection should
 // be re-used or not. If an error occurs, by default we don't reuse the
@@ -133,6 +136,14 @@ type Client struct {
 	// If zero, DefaultTimeout is used.
 	Timeout time.Duration
 
+	// MaxIdleConns specifies the maximum number of idle connections that will
+	// be maintained per address. If less than one, DefaultMaxIdleConns will be
+	// used.
+	//
+	// Consider your expected traffic rates and latency carefully. This should
+	// be set to a number higher than your peak parallel requests.
+	MaxIdleConns int
+
 	selector ServerSelector
 
 	lk       sync.Mutex
@@ -196,7 +207,7 @@ func (c *Client) putFreeConn(addr net.Addr, cn *conn) {
 		c.freeconn = make(map[string][]*conn)
 	}
 	freelist := c.freeconn[addr.String()]
-	if len(freelist) >= maxIdleConnsPerAddr {
+	if len(freelist) >= c.maxIdleConns() {
 		cn.nc.Close()
 		return
 	}
@@ -225,6 +236,13 @@ func (c *Client) netTimeout() time.Duration {
 	return DefaultTimeout
 }
 
+func (c *Client) maxIdleConns() int {
+	if c.MaxIdleConns > 0 {
+		return c.MaxIdleConns
+	}
+	return DefaultMaxIdleConns
+}
+
 // ConnectTimeoutError is the error type used when it takes
 // too long to connect to the desired host. This level of
 // detail can generally be ignored.

+ 33 - 0
memcache/memcache_test.go

@@ -18,7 +18,10 @@ limitations under the License.
 package memcache
 
 import (
+	"bufio"
 	"fmt"
+	"io"
+	"io/ioutil"
 	"net"
 	"os"
 	"os/exec"
@@ -254,3 +257,33 @@ func testTouchWithClient(t *testing.T, c *Client) {
 		}
 	}
 }
+
+func BenchmarkOnItem(b *testing.B) {
+	fakeServer, err := net.Listen("tcp", "localhost:0")
+	if err != nil {
+		b.Fatal("Could not open fake server: ", err)
+	}
+	defer fakeServer.Close()
+	go func() {
+		for {
+			if c, err := fakeServer.Accept(); err == nil {
+				go func() { io.Copy(ioutil.Discard, c) }()
+			} else {
+				return
+			}
+		}
+	}()
+
+	addr := fakeServer.Addr()
+	c := New(addr.String())
+	if _, err := c.getConn(addr); err != nil {
+		b.Fatal("failed to initialize connection to fake server")
+	}
+
+	item := Item{Key: "foo"}
+	dummyFn := func(_ *Client, _ *bufio.ReadWriter, _ *Item) error { return nil }
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		c.onItem(&item, dummyFn)
+	}
+}

+ 17 - 2
memcache/selector.go

@@ -41,6 +41,21 @@ type ServerList struct {
 	addrs []net.Addr
 }
 
+// staticAddr caches the Network() and String() values from any net.Addr.
+type staticAddr struct {
+	ntw, str string
+}
+
+func newStaticAddr(a net.Addr) net.Addr {
+	return &staticAddr{
+		ntw: a.Network(),
+		str: a.String(),
+	}
+}
+
+func (s *staticAddr) Network() string { return s.ntw }
+func (s *staticAddr) String() string  { return s.str }
+
 // SetServers changes a ServerList's set of servers at runtime and is
 // safe for concurrent use by multiple goroutines.
 //
@@ -58,13 +73,13 @@ func (ss *ServerList) SetServers(servers ...string) error {
 			if err != nil {
 				return err
 			}
-			naddr[i] = addr
+			naddr[i] = newStaticAddr(addr)
 		} else {
 			tcpaddr, err := net.ResolveTCPAddr("tcp", server)
 			if err != nil {
 				return err
 			}
-			naddr[i] = tcpaddr
+			naddr[i] = newStaticAddr(tcpaddr)
 		}
 	}