@marcel91200 / caddy Mirror · read-only / commits / f42b138f
Fork 0

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)