Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 14, 05:15 UTC
tls: Avoid duplication AutomationPolicies for large quantities of names
This should greatly reduce memory usage at scale. Part of an overall effort between Caddy 2 and CertMagic to optimize for large numbers of names.
Matthew Holt committed
Feb 14, 2020 at 11:14 UTC
f42b138fb18d080861f70e831c479738e3cdcd14
3 files changed
+25
-12
caddyconfig/httpcaddyfile/httptype.go
+3
-3
@@ -200,7 +200,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
200
if tlsApp.Automation == nil {
201
tlsApp.Automation = new(caddytls.AutomationConfig)
202
}
203
- tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, caddytls.AutomationPolicy{
203
+ tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, &caddytls.AutomationPolicy{
204
Hosts: sblockHosts,
205
ManagementRaw: caddyconfig.JSONModuleObject(mm, "module", mm.(caddy.Module).CaddyModule().ID.Name(), &warnings),
206
})
@@ -251,7 +251,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
251
DNSRaw: caddyconfig.JSONModuleObject(dnsProvModule.New(), "provider", provName, &warnings),
252
}
253
}
254
- tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, caddytls.AutomationPolicy{
254
+ tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, &caddytls.AutomationPolicy{
255
ManagementRaw: caddyconfig.JSONModuleObject(mgr, "module", "acme", &warnings),
256
})
257
}
@@ -593,7 +593,7 @@ func consolidateRoutes(routes caddyhttp.RouteList) caddyhttp.RouteList {
593
594
// consolidateAutomationPolicies combines automation policies that are the same,
595
// for a cleaner overall output.
596
-func consolidateAutomationPolicies(aps []caddytls.AutomationPolicy) []caddytls.AutomationPolicy {
596
+func consolidateAutomationPolicies(aps []*caddytls.AutomationPolicy) []*caddytls.AutomationPolicy {
597
for i := 0; i < len(aps); i++ {
598
for j := 0; j < len(aps); j++ {
599
if j == i {
modules/caddyhttp/autohttps.go
+1
-1
@@ -338,7 +338,7 @@ func (app *App) automaticHTTPSPhase3() error {
338
srv.tlsApp.Automation = new(caddytls.AutomationConfig)
339
}
340
srv.tlsApp.Automation.Policies = append(srv.tlsApp.Automation.Policies,
341
- caddytls.AutomationPolicy{
341
+ &caddytls.AutomationPolicy{
342
Hosts: domainsForCerts,
343
Management: acmeManager,
344
})
modules/caddytls/tls.go
+21
-8
@@ -202,19 +202,32 @@ func (t *TLS) Cleanup() error {
202
// Manage immediately begins managing names according to the
203
// matching automation policy.
204
func (t *TLS) Manage(names []string) error {
205
+ // for a large number of names, we can be more memory-efficient
206
+ // by making only one certmagic.Config for all the names that
207
+ // use that config, rather than calling ManageSync/ManageAsync
208
+ // once for every name; so first, bin names by AutomationPolicy
209
+ policyToNames := make(map[*AutomationPolicy][]string)
210
for _, name := range names {
211
ap := t.getAutomationPolicyForName(name)
212
+ policyToNames[ap] = append(policyToNames[ap], name)
213
+ }
214
+
215
+ // now that names are grouped by policy, we can simply make one
216
+ // certmagic.Config for each (potentially large) group of names
217
+ // and call ManageSync/ManageAsync just once for the whole batch
218
+ for ap, names := range policyToNames {
219
magic := certmagic.New(t.certCache, ap.makeCertMagicConfig(t.ctx))
220
var err error
221
if ap.ManageSync {
210
- err = magic.ManageSync([]string{name})
222
+ err = magic.ManageSync(names)
223
} else {
212
- err = magic.ManageAsync(t.ctx.Context, []string{name})
224
+ err = magic.ManageAsync(t.ctx.Context, names)
225
}
226
if err != nil {
215
- return fmt.Errorf("automate: manage %s: %v", name, err)
227
+ return fmt.Errorf("automate: manage %v: %v", names, err)
228
}
229
}
230
+
231
return nil
232
}
233
@@ -234,7 +247,7 @@ func (t *TLS) getConfigForName(name string) (certmagic.Config, error) {
247
return ap.makeCertMagicConfig(t.ctx), nil
248
}
249
237
-func (t *TLS) getAutomationPolicyForName(name string) AutomationPolicy {
250
+func (t *TLS) getAutomationPolicyForName(name string) *AutomationPolicy {
251
if t.Automation != nil {
252
for _, ap := range t.Automation.Policies {
253
if len(ap.Hosts) == 0 {
@@ -248,9 +261,7 @@ func (t *TLS) getAutomationPolicyForName(name string) AutomationPolicy {
261
}
262
}
263
}
251
-
252
- // default automation policy
253
- return AutomationPolicy{Management: new(ACMEManagerMaker)}
264
+ return defaultAutomationPolicy
265
}
266
267
// AllMatchingCertificates returns the list of all certificates in
@@ -329,7 +340,7 @@ type Certificate struct {
340
type AutomationConfig struct {
341
// The list of automation policies. The first matching
342
// policy will be applied for a given certificate/name.
332
- Policies []AutomationPolicy `json:"policies,omitempty"`
343
+ Policies []*AutomationPolicy `json:"policies,omitempty"`
344
345
// On-Demand TLS defers certificate operations to the
346
// moment they are needed, e.g. during a TLS handshake.
@@ -510,6 +521,8 @@ var (
521
storageCleanMu sync.Mutex
522
)
523
524
+var defaultAutomationPolicy = &AutomationPolicy{Management: new(ACMEManagerMaker)}
525
+
526
// Interface guards
527
var (
528
_ caddy.App = (*TLS)(nil)