summaryrefslogtreecommitdiff
path: root/modules/caddytls
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2020-02-14 11:14:52 -0700
committerMatthew Holt <mholt@users.noreply.github.com>2020-02-14 11:14:52 -0700
commitf42b138fb18d080861f70e831c479738e3cdcd14 (patch)
tree13215d6c6fc111162baeb080428fd3b48ecc71ee /modules/caddytls
parent2cc5d2227dd8b8ad2d71112709ec29ab34fcd0ea (diff)
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.
Diffstat (limited to 'modules/caddytls')
-rw-r--r--modules/caddytls/tls.go29
1 files changed, 21 insertions, 8 deletions
diff --git a/modules/caddytls/tls.go b/modules/caddytls/tls.go
index f9beb6f..7d80bfb 100644
--- a/modules/caddytls/tls.go
+++ b/modules/caddytls/tls.go
@@ -202,19 +202,32 @@ func (t *TLS) Cleanup() error {
// Manage immediately begins managing names according to the
// matching automation policy.
func (t *TLS) Manage(names []string) error {
+ // for a large number of names, we can be more memory-efficient
+ // by making only one certmagic.Config for all the names that
+ // use that config, rather than calling ManageSync/ManageAsync
+ // once for every name; so first, bin names by AutomationPolicy
+ policyToNames := make(map[*AutomationPolicy][]string)
for _, name := range names {
ap := t.getAutomationPolicyForName(name)
+ policyToNames[ap] = append(policyToNames[ap], name)
+ }
+
+ // now that names are grouped by policy, we can simply make one
+ // certmagic.Config for each (potentially large) group of names
+ // and call ManageSync/ManageAsync just once for the whole batch
+ for ap, names := range policyToNames {
magic := certmagic.New(t.certCache, ap.makeCertMagicConfig(t.ctx))
var err error
if ap.ManageSync {
- err = magic.ManageSync([]string{name})
+ err = magic.ManageSync(names)
} else {
- err = magic.ManageAsync(t.ctx.Context, []string{name})
+ err = magic.ManageAsync(t.ctx.Context, names)
}
if err != nil {
- return fmt.Errorf("automate: manage %s: %v", name, err)
+ return fmt.Errorf("automate: manage %v: %v", names, err)
}
}
+
return nil
}
@@ -234,7 +247,7 @@ func (t *TLS) getConfigForName(name string) (certmagic.Config, error) {
return ap.makeCertMagicConfig(t.ctx), nil
}
-func (t *TLS) getAutomationPolicyForName(name string) AutomationPolicy {
+func (t *TLS) getAutomationPolicyForName(name string) *AutomationPolicy {
if t.Automation != nil {
for _, ap := range t.Automation.Policies {
if len(ap.Hosts) == 0 {
@@ -248,9 +261,7 @@ func (t *TLS) getAutomationPolicyForName(name string) AutomationPolicy {
}
}
}
-
- // default automation policy
- return AutomationPolicy{Management: new(ACMEManagerMaker)}
+ return defaultAutomationPolicy
}
// AllMatchingCertificates returns the list of all certificates in
@@ -329,7 +340,7 @@ type Certificate struct {
type AutomationConfig struct {
// The list of automation policies. The first matching
// policy will be applied for a given certificate/name.
- Policies []AutomationPolicy `json:"policies,omitempty"`
+ Policies []*AutomationPolicy `json:"policies,omitempty"`
// On-Demand TLS defers certificate operations to the
// moment they are needed, e.g. during a TLS handshake.
@@ -510,6 +521,8 @@ var (
storageCleanMu sync.Mutex
)
+var defaultAutomationPolicy = &AutomationPolicy{Management: new(ACMEManagerMaker)}
+
// Interface guards
var (
_ caddy.App = (*TLS)(nil)