Memory usage with lua_ssl_trusted_certificate and multiple server blocks

518 views
Skip to first unread message

Hamish Forbes

unread,
May 19, 2015, 8:47:24 AM5/19/15
to openre...@googlegroups.com
Hi,

I'm seeing issue where the trusted CA cert file seems to be loaded into memory for every server {} block defined with an SSL listen.
Here's a gist with a minimal config and some system details: http://gist.github.com/hamishforbes/d2d0d3ccc5ab1fbed565

As you can see ~60 ssl server blocks ends up using ~60MB per worker with a 770KB CA bundle.
Also HUP'ing the master process approximately doubles the worker memory usage.
It also makes workers very slow to startup.

This doesn't seem to happen on OS X, or if you have many ssl listen directives within the same server block.
I also tried compiling from scratch on this particular system as we install Openresty from an RPM, with no difference.

A little background, we need to terminate many different SSL hostnames via SNI on this server hence ~60 server blocks.
We also need to proxy to HTTPS endpoints with the Lua tcp cosocket API and want to be able to verify these endpoints.
As such lua_ssl_trusted_certificate is pointed at the OS's CA cert bundle (/etc/pki/tls/cert.pem on Redhat systems) with is around 770KB.

Is this expected behaviour or a bug? 
If expected is there anything we can do to work around it other than reducing the size of the trusted certs bundle?

Thanks
Hamish

Yichun Zhang (agentzh)

unread,
May 27, 2015, 11:34:09 AM5/27/15
to openresty-en
Hello!

On Tue, May 19, 2015 at 8:47 PM, Hamish Forbes wrote:
> I'm seeing issue where the trusted CA cert file seems to be loaded into
> memory for every server {} block defined with an SSL listen.

Yes, the OpenSSL context is per-server according to the current
implementation. So this is the expected behavior.

> As you can see ~60 ssl server blocks ends up using ~60MB per worker with a
> 770KB CA bundle.
> Also HUP'ing the master process approximately doubles the worker memory
> usage.
> It also makes workers very slow to startup.
>

The HUP thing should just be an artifact of (temporary) memory
fragmentation. Try keeping sending HUP to see if the memory grows
infinitely. It shouldn't be the case.

> This doesn't seem to happen on OS X,

Maybe different OpenSSL version? Or just OS X is better on handling
memory fragmentation in this very specific case?

> A little background, we need to terminate many different SSL hostnames via
> SNI on this server hence ~60 server blocks.

Seems like it's something you really need ssl_certificate_by_lua instead:



We have WAY more different SSL certificate/private-key pairs on each
production box with just a single server {} block in nginx.conf at
CloudFlare.

> We also need to proxy to HTTPS endpoints with the Lua tcp cosocket API and
> want to be able to verify these endpoints.
> As such lua_ssl_trusted_certificate is pointed at the OS's CA cert bundle
> (/etc/pki/tls/cert.pem on Redhat systems) with is around 770KB.
>

Also, try reducing the default root CA cert bundle to the minimum is
also a good idea. But as mentioned above, I really think you should
avoid so many server {} blocks in nginx.conf in the first place.

> Is this expected behaviour or a bug?

This is the expected behavior over all :)

> If expected is there anything we can do to work around it other than
> reducing the size of the trusted certs bundle?
>

See above. Regarding reducing the trusted cert bundle, you can
re-generate such bundles yourself by removing ones you don't really
need. Having said that, try combining your 60 server {} blocks into a
single one with ssl_certificate_by_lua first :)

Regards,
-agentzh

P.S. I'm very sorry for the late reply. I've been on vacation in China.

Yichun Zhang (agentzh)

unread,
May 27, 2015, 11:35:11 AM5/27/15
to openresty-en
Hello!

On Wed, May 27, 2015 at 11:34 PM, Yichun Zhang (agentzh) wrote:
> Seems like it's something you really need ssl_certificate_by_lua instead:
>

Oops, I forgot the link here:

https://github.com/openresty/lua-nginx-module/issues/331#issuecomment-77279170

Best regards,
-agentzh

Hamish Forbes

unread,
May 28, 2015, 5:15:57 AM5/28/15
to openre...@googlegroups.com


On Wednesday, 27 May 2015 16:34:09 UTC+1, agentzh wrote:

Yes, the OpenSSL context is per-server according to the current
implementation. So this is the expected behavior.

Ok, that makes sense.
How does the lua_ssl_trusted_certificate differ from vanilla nginx's proxy_ssl_trusted_certificate option?
I don't see the same behaviour there and while I don't claim to understand the nginx C code at all, they appear very similar features.


The HUP thing should just be an artifact of (temporary) memory
fragmentation. Try keeping sending HUP to see if the memory grows
infinitely. It shouldn't be the case.

Yep, it doubles on the first HUP and then stays there.
 

Maybe different OpenSSL version? Or just OS X is better on handling
memory fragmentation in this very specific case?

Yeah on OS X its OpenSSL 0.9.8zd and 1.0.1e-fips on my Linux box.

I can see how OS Xs memory system could account for the difference after HUPing, but it's interesting that I don't see the increased initial memory use either.
I was going to test it out on a FreeBSD VM and building against some different versions of OpenSSL as well, but never got around to it.
 

Seems like it's something you really need ssl_certificate_by_lua instead:

Yep! Been following that feature for a while, that's definitely the long term goal.
I was waiting for a new release of Openresty that included that feature first though.
 

See above. Regarding reducing the trusted cert bundle, you can
re-generate such bundles yourself by removing ones you don't really
need. Having said that, try combining your 60 server {} blocks into a
single one with ssl_certificate_by_lua first :)

I think for the time being I'm just going to disable ssl verification on origin connections until we start using ssl_certificate_by_lua.

 

Regards,
-agentzh

P.S. I'm very sorry for the late reply. I've been on vacation in China.

No problem, thanks for the explanation!


Hamish
 

Yichun Zhang (agentzh)

unread,
May 28, 2015, 9:02:41 AM5/28/15
to openresty-en
Hello!

On Thu, May 28, 2015 at 5:15 PM, Hamish Forbes wrote:
> How does the lua_ssl_trusted_certificate differ from vanilla nginx's
> proxy_ssl_trusted_certificate option?

IIRC, there isn't any difference at all. I simply stole the code from
ngx_proxy :) But I don't have the code off hand, so feel free to prove
me wrong.

> I don't see the same behaviour there and while I don't claim to understand
> the nginx C code at all, they appear very similar features.
>

It'll be easier for me if you could provide a standalone and minimal
example that can easily reproduce the "issues" on my side.

>
> Yep, it doubles on the first HUP and then stays there.
>

So that explains :)

> I can see how OS Xs memory system could account for the difference after
> HUPing, but it's interesting that I don't see the increased initial memory
> use either.

Maybe OS X is just a bit lucky in this case :) I dunno.

>
> Yep! Been following that feature for a while, that's definitely the long
> term goal.
> I was waiting for a new release of Openresty that included that feature
> first though.
>

Yeah, it'll take some time on my side :)

Best regards,
-agentzh

Hamish Forbes

unread,
May 28, 2015, 9:35:21 AM5/28/15
to openre...@googlegroups.com
Hi,

The gist contains a minimal nginx.conf that shows the issue on my side, all you need a reasonably large cert.pem
https://gist.github.com/hamishforbes/d2d0d3ccc5ab1fbed565#file-nginx-conf

What I see with that config is ~3MB resident memory with both options commented out.
~60MB with the Lua option enabled and ~3MB with the proxy option enabled.

Hamish

Hamish Forbes

unread,
May 28, 2015, 9:42:12 AM5/28/15
to openre...@googlegroups.com
Ah, actually...
If you have proxy_ssl_trusted_certificate set to a large ca bundle, proxy_ssl_verify set to on 
*and* have proxy_pass configured in the server blocks then you get the same ~60MB memory usage.

Which makes sense.

Hamish

Elvin Efendi

unread,
Mar 4, 2017, 7:07:24 PM3/4/17
to openresty-en
Hello,

I recently ran into the similar issue with `lua_ssl_trusted_certificate`. I have a big nginx.conf file with over 4k `location` definitions and it turns out that `ngx_lua` loads the certificate file per each location. This is problematic because of the memory trick `ngx_lua` does at https://github.com/openresty/lua-nginx-module/blob/37e5362088bd659e318aae568b268719bd0d6707/src/ngx_http_lua_module.c#L1294 on Linux hosts(hence the memory growth is not problematic on OSX). Because that memory trick creates a "hole", all subsequent `(s)brk` calls(in this example from Openssl while loading the certificate file into memory) fails and `malloc` automatically uses `mmap` instead and allocates 1024x1024 bytes(to decrease number of potential `mmap` calls: https://code.woboq.org/userspace/glibc/malloc/malloc.c.html#406). In my case because of this was happening for all `location` sections Nginx memory consumption grew to 4k * 1024 * 1024 ~= 5GB, which triggered out of memory killer to kill Nginx process.
Note: I need the trusted certificate only in init worker phase but because of this behaviour I redundantly load it per every `location` section defined.

Here are some possible solutions I can think of:
1. Add an option to ssl handshake function to be able to pass the path to certificate file.
2. Change the behaviour of `lua_ssl_trusted_certificate` directive to be more like Nginx's `ssl_trusted_certificate` and be loaded only per `server` block.
3. Share Openssl's `cert_store` object between different `ssl` objects when `lua_ssl_trusted_certificate` is same. But this complicated and can be problematic because making `cert_store` thread safe is not easy as per my research.

@agentzh what do you think?

Also I'd be very thankful if you can point me to an article where I can learn how does that memory trick ensures that Luajit will use as much lower address space as possible.

Thanks :)

Elvin Efendi

unread,
Mar 4, 2017, 7:32:07 PM3/4/17
to openresty-en
another option would be calling `malloc_trim` every time a location configuration gets merged.
Reply all
Reply to author
Forward
0 new messages