Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d46763c

Browse files
committed
Increase bindcache capacity (linkerd#457)
* Increase bindcache capacity * Allow binding cache sizes to be configurable on the linkerd and namerd sides
1 parent 43eff79 commit d46763c

File tree

10 files changed

+135
-10
lines changed

10 files changed

+135
-10
lines changed

linkerd/core/src/main/scala/io/buoyant/linkerd/Router.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ trait RouterConfig {
142142
@JsonIgnore
143143
def bindingTimeout = _bindingTimeoutMs.map(_.millis).getOrElse(10.seconds)
144144

145+
/*
146+
* binding cache size
147+
*/
148+
149+
var bindingCache: Option[BindingCacheConfig] = None
150+
145151
/*
146152
* responseClassifier categorizes responses to determine whether
147153
* they are failures and if they are retryable.
@@ -174,6 +180,7 @@ trait RouterConfig {
174180
.maybeWith(failFast.map(FailFastFactory.FailFast(_)))
175181
.maybeWith(timeoutMs.map(timeout => TimeoutFilter.Param(timeout.millis)))
176182
.maybeWith(dstPrefix.map(pfx => RoutingFactory.DstPrefix(Path.read(pfx))))
183+
.maybeWith(bindingCache.map(_.capacity))
177184
.maybeWith(client.map(_.clientParams)) +
178185
param.ResponseClassifier(responseClassifier) +
179186
param.Label(label) +
@@ -288,3 +295,19 @@ case class HostConnectionPool(
288295
maxWaiters = maxWaiters.getOrElse(default.maxWaiters)
289296
)
290297
}
298+
299+
case class BindingCacheConfig(
300+
paths: Option[Int],
301+
trees: Option[Int],
302+
bounds: Option[Int],
303+
clients: Option[Int]
304+
) {
305+
private[this] val default = DstBindingFactory.Capacity.default
306+
307+
def capacity = DstBindingFactory.Capacity(
308+
paths = paths.getOrElse(default.paths),
309+
trees = trees.getOrElse(default.trees),
310+
bounds = bounds.getOrElse(default.bounds),
311+
clients = clients.getOrElse(default.clients)
312+
)
313+
}

linkerd/core/src/test/scala/io/buoyant/linkerd/RouterTest.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,19 @@ servers:
122122
Some(RetryBudgetConfig(Some(30), Some(3), Some(0.33)))
123123
)))
124124
}
125+
126+
test("with binding cache") {
127+
val yaml =
128+
"""|protocol: plain
129+
|bindingCache:
130+
| paths: 1000
131+
| trees: 999
132+
| bounds: 998
133+
|""".stripMargin
134+
val capacity = parseConfig(yaml).routerParams[DstBindingFactory.Capacity]
135+
assert(capacity.paths == 1000)
136+
assert(capacity.trees == 999)
137+
assert(capacity.bounds == 998)
138+
assert(capacity.clients == DstBindingFactory.Capacity.default.clients)
139+
}
125140
}

linkerd/docs/config.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ Each router must be configured as an object with the following params:
151151
* *timeoutMs* -- Per-request timeout in milliseconds. (default: no timeout)
152152
* *bindingTimeoutMs* -- Optional. The maximum amount of time in milliseconds to
153153
spend binding a path. (default: 10 seconds)
154+
* *bindingCache* -- Optional. Configure the size of binding cache. It must be
155+
an object containing keys:
156+
* *paths* -- Optional. Size of the path cache. (default: 100)
157+
* *trees* -- Optional. Size of the tree cache. (default: 100)
158+
* *bounds* -- Optional. Size of the bound cache. (default: 100)
159+
* *clients* -- Optional. Size of the client cache. (default: 10)
154160

155161
<a name="basic-server-params"></a>
156162
### Basic server parameters

namerd/docs/interface.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ A read-only interface providing `NameInterpreter` functionality over the ThriftM
2323
before retrying after an error. (default: 600)
2424
* *retryJitterSecs* -- Optional. Maximum number of seconds to jitter retry
2525
time by. (default: 60)
26+
* *cache* -- Optional. Configure the size of the binding and address caches.
27+
It must be an object containing keys:
28+
* *bindingCacheActive* -- Optional. The size of the binding active cache.
29+
(default: 1000)
30+
* *bindingCacheInactive* -- Optional. The size of the binding inactive cache.
31+
(default: 100)
32+
* *addrCacheActive* -- Optional. The size of the address active cache.
33+
(default: 1000)
34+
* *addrCacheInactive* -- Optional. The size of the address inactive cache.
35+
(default: 100)
2636

2737
## Http Controller
2838

namerd/iface/interpreter-thrift/src/main/scala/io/buoyant/namerd/iface/ThriftInterpreterInterfaceConfig.scala

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import scala.util.Random
1414

1515
case class ThriftInterpreterInterfaceConfig(
1616
retryBaseSecs: Option[Int] = None,
17-
retryJitterSecs: Option[Int] = None
17+
retryJitterSecs: Option[Int] = None,
18+
cache: Option[CapacityConfig] = None
1819
) extends InterpreterInterfaceConfig {
1920
@JsonIgnore
2021
protected def defaultAddr = ThriftInterpreterInterfaceConfig.defaultAddr
@@ -31,7 +32,14 @@ case class ThriftInterpreterInterfaceConfig(
3132
val jitter = retryJitterSecs.map(_.seconds).getOrElse(1.minute)
3233
() => retry + (Random.nextGaussian() * jitter.inSeconds).toInt.seconds
3334
}
34-
val iface = new ThriftNamerInterface(interpreters, namers, new LocalStamper, retryIn, stats)
35+
val iface = new ThriftNamerInterface(
36+
interpreters,
37+
namers,
38+
new LocalStamper,
39+
retryIn,
40+
cache.map(_.capacity).getOrElse(ThriftNamerInterface.Capacity.default),
41+
stats
42+
)
3543
ThriftServable(addr, iface)
3644
}
3745
}
@@ -50,3 +58,19 @@ case class ThriftServable(addr: InetSocketAddress, iface: ThriftService) extends
5058
def kind = ThriftInterpreterInterfaceConfig.kind
5159
def serve() = ThriftMux.server.serveIface(addr, iface)
5260
}
61+
62+
case class CapacityConfig(
63+
bindingCacheActive: Option[Int] = None,
64+
bindingCacheInactive: Option[Int] = None,
65+
addrCacheActive: Option[Int] = None,
66+
addrCacheInactive: Option[Int] = None
67+
) {
68+
private[this] val default = ThriftNamerInterface.Capacity.default
69+
70+
def capacity = ThriftNamerInterface.Capacity(
71+
bindingCacheActive = bindingCacheActive.getOrElse(default.bindingCacheActive),
72+
bindingCacheInactive = bindingCacheInactive.getOrElse(default.bindingCacheInactive),
73+
addrCacheActive = addrCacheActive.getOrElse(default.addrCacheActive),
74+
addrCacheInactive = addrCacheInactive.getOrElse(default.addrCacheInactive)
75+
)
76+
}

namerd/iface/interpreter-thrift/src/main/scala/io/buoyant/namerd/iface/ThriftNamerInterface.scala

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.twitter.finagle.{Addr, Address, Dtab, Name, Namer, NameTree, Path}
77
import com.twitter.io.Buf
88
import com.twitter.logging.Logger
99
import com.twitter.util._
10+
import io.buoyant.namerd.iface.ThriftNamerInterface.Capacity
1011
import io.buoyant.namerd.iface.{thriftscala => thrift}
1112
import io.buoyant.namerd.Ns
1213
import java.nio.ByteBuffer
@@ -206,6 +207,22 @@ object ThriftNamerInterface {
206207
}
207208

208209
private val DefaultNamer: (Path, Namer) = Path.empty -> Namer.global
210+
211+
case class Capacity(
212+
bindingCacheActive: Int,
213+
bindingCacheInactive: Int,
214+
addrCacheActive: Int,
215+
addrCacheInactive: Int
216+
)
217+
218+
object Capacity {
219+
def default = Capacity(
220+
bindingCacheActive = 1000,
221+
bindingCacheInactive = 100,
222+
addrCacheActive = 1000,
223+
addrCacheInactive = 100
224+
)
225+
}
209226
}
210227

211228
/**
@@ -216,6 +233,7 @@ class ThriftNamerInterface(
216233
namers: Map[Path, Namer],
217234
stamper: ThriftNamerInterface.Stamper,
218235
retryIn: () => Duration,
236+
capacity: Capacity,
219237
stats: StatsReceiver
220238
) extends thrift.Namer.FutureIface {
221239
import ThriftNamerInterface._
@@ -262,8 +280,8 @@ class ThriftNamerInterface(
262280
private[this] def observeBind(ns: Ns, dtab: Dtab, path: Path) =
263281
BindingObserver(interpreters(ns).bind(dtab, path), stamper)
264282
private[this] val bindingCache = new ObserverCache[(String, Dtab, Path), NameTree[Name.Bound]](
265-
activeCapacity = 100,
266-
inactiveCapacity = 10,
283+
activeCapacity = capacity.bindingCacheActive,
284+
inactiveCapacity = capacity.bindingCacheInactive,
267285
stats = stats.scope("bindindcache"),
268286
mkObserver = (observeBind _).tupled
269287
)
@@ -337,8 +355,8 @@ class ThriftNamerInterface(
337355
AddrObserver(resolution, stamper)
338356
}
339357
private[this] val addrCache = new ObserverCache[Path, Option[Addr.Bound]](
340-
activeCapacity = 100,
341-
inactiveCapacity = 10,
358+
activeCapacity = capacity.addrCacheActive,
359+
inactiveCapacity = capacity.addrCacheInactive,
342360
stats = stats.scope("addrcache"),
343361
mkObserver = observeAddr
344362
)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.buoyant.namerd.iface
2+
3+
import io.buoyant.config.Parser
4+
import org.scalatest.FunSuite
5+
6+
class ThriftInterpreterInterfaceConfigTest extends FunSuite {
7+
8+
test("cache capacity") {
9+
val yaml = """
10+
|kind: io.l5d.thriftNameInterpreter
11+
|cache:
12+
| bindingCacheActive: 5000
13+
| bindingCacheInactive: 1000
14+
| addrCacheActive: 6000
15+
""".stripMargin
16+
17+
val config = Parser
18+
.objectMapper(
19+
yaml,
20+
Iterable(Seq(new ThriftInterpreterInterfaceInitializer))
21+
).readValue[ThriftInterpreterInterfaceConfig](yaml)
22+
23+
val capacity = config.cache.get.capacity
24+
assert(capacity.bindingCacheActive == 5000)
25+
assert(capacity.bindingCacheInactive == 1000)
26+
assert(capacity.addrCacheActive == 6000)
27+
assert(capacity.addrCacheInactive == ThriftNamerInterface.Capacity.default.addrCacheInactive)
28+
}
29+
}

namerd/iface/interpreter-thrift/src/test/scala/io/buoyant/namerd/iface/ThriftNamerEndToEndTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class ThriftNamerEndToEndTest extends FunSuite with Eventually with IntegrationP
4747
else Activity.exception(new Exception)
4848
}
4949
val namers = Map(Path.read("/io.l5d.w00t") -> namer)
50-
val service = new ThriftNamerInterface(interpreter, namers, newStamper, retryIn, NullStatsReceiver)
50+
val service = new ThriftNamerInterface(interpreter, namers, newStamper, retryIn, Capacity.default, NullStatsReceiver)
5151
val client = new ThriftNamerClient(service, ns, clientId)
5252

5353
val act = client.bind(reqDtab, reqPath)

namerd/iface/interpreter-thrift/src/test/scala/io/buoyant/namerd/iface/ThriftNamerInterfaceTest.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class ThriftNamerInterfaceTest extends FunSuite {
2525
}
2626
val stampCounter = new AtomicLong(1)
2727
def stamper() = Stamp.mk(stampCounter.getAndIncrement)
28-
val service = new ThriftNamerInterface(interpreter, Map.empty, stamper, retryIn, NullStatsReceiver)
28+
val service = new ThriftNamerInterface(interpreter, Map.empty, stamper, retryIn, Capacity.default, NullStatsReceiver)
2929

3030
// The first request before the tree has been refined -- no value initially
3131
val initName = thrift.NameRef(TStamp.empty, TPath("ysl", "thugger"), ns)
@@ -72,7 +72,7 @@ class ThriftNamerInterfaceTest extends FunSuite {
7272
val namers = Map(pfx -> new Namer { def lookup(path: Path) = Activity(states) })
7373
val stampCounter = new AtomicLong(1)
7474
def stamper() = Stamp.mk(stampCounter.getAndIncrement)
75-
val service = new ThriftNamerInterface(interpreter, namers, stamper, retryIn, NullStatsReceiver)
75+
val service = new ThriftNamerInterface(interpreter, namers, stamper, retryIn, Capacity.default, NullStatsReceiver)
7676
}
7777

7878
test("addr") {

router/core/src/main/scala/com/twitter/finagle/buoyant/DstBindingFactory.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ object DstBindingFactory {
106106
}
107107

108108
implicit object Capacity extends Stack.Param[Capacity] {
109-
val default = Capacity(50, 50, 50, 5)
109+
val default = Capacity(100, 100, 100, 10)
110110
}
111111

112112
case class BindingTimeout(timeout: Duration)

0 commit comments

Comments
 (0)