Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set useOpenSsl in Flags lazily to reduce server startup time #2184

Merged
merged 12 commits into from
Oct 25, 2019
Merged

Set useOpenSsl in Flags lazily to reduce server startup time #2184

merged 12 commits into from
Oct 25, 2019

Conversation

mumgmangmange
Copy link
Contributor

@mumgmangmange mumgmangmange commented Oct 12, 2019

Motivation:
Related #1645
useOpenSsl in Flags is used only when TLS is enabled. However, it takes a lot to instantiate OpenSsl class so it adds up a tremendous time to the server startup time. We should fix to instantiate it only when it needs.

Modification:

  • Set useOpenSsl in Flags lazily
  • Check whether the OS is Linux before calling Epoll.isAvailable()
  • Add OsType

Result:

  • Reduced server startup time to 80 percent (20% decreased)

@minwoox minwoox mentioned this pull request Oct 14, 2019
@minwoox minwoox changed the title Issue 164501 Set USE_OPENSSL and USE_EPOLL in Flags when they need Oct 14, 2019
Copy link
Contributor

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Way to go @mumgmangmange!
Let's initiate USE_EPOLL lazily as we do for USE_OPENSSL.
Also, if you let us know how much the server startup time decreases, that'll be much appreciated.


private static final boolean USE_OPENSSL = getBoolean("useOpenSsl", OpenSsl.isAvailable(),
value -> OpenSsl.isAvailable() || !value);
private static Boolean USE_OPENSSL = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need to synchronize to set this value but I think we still need to make this volatile because some of the threads might not see this. /cc @trustin, @ikhoon

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is not a static final constant anymore, we should use camel case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you leave a comment about why we initialize this field lazily?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to Camel. Thank you.

Do not call OpenSsl.isAvailable() when not using SSL.
0.2 to 0.3 seconds shortened.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this change be in a patch release with boot 2.2? If it is that much overhead, this will reduce zipkin-slim startup by 15% (I can verify). We are nearing a redo of our release, and it would make the announcement much better I think.

cc @trustin @anuraaga

@minwoox minwoox added this to the 0.95.0 milestone Oct 14, 2019
@minwoox minwoox changed the title Set USE_OPENSSL and USE_EPOLL in Flags when they need Set useOpenSsl in Flags lazily to reduce server startup time Oct 15, 2019
Comment on lines 312 to 313
// Netty epoll transport does not work with WSL (Windows Sybsystem for Linux) yet.
// TODO(trustin): Re-enable on WSL if https://github.com/Microsoft/WSL/issues/1982 is resolved.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this comment inside the if block below for readability.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed. Thank you. 😄

@trustin
Copy link
Member

trustin commented Oct 17, 2019

There are 3 Checkstyle violations:

[ant:checkstyle] [ERROR] /appveyor/projects/armeria/core/src/main/java/com/linecorp/armeria/common/Flags.java:120:28: Variable 'USE_OPENSSL' explicitly initialized to 'null' (default value for its type). [ExplicitInitialization]
[ant:checkstyle] [ERROR] /appveyor/projects/armeria/core/src/main/java/com/linecorp/armeria/common/Flags.java:412: Line is longer than 112 characters (found 116). [LineLength]
[ant:checkstyle] [ERROR] /appveyor/projects/armeria/core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java:84:8: Unused import - io.netty.handler.ssl.OpenSsl. [UnusedImports]

Just in case it's unclear, the first violation means you do not need to assign null to a variable, because a variable's default value is null already. The other two look obvious, right?

@CLAassistant
Copy link

CLAassistant commented Oct 17, 2019

CLA assistant check
All committers have signed the CLA.

/**
* Return whether Linux is used.
*/
public static boolean isLinux() {
return Ascii.toLowerCase(System.getProperty("os.name", "")).startsWith("linux");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that this is a public method, we should go ahead and optimize the method. Can you add private static final boolean IS_LINUX = Ascii.toLowerCase(System.getProperty("os.name", "")).startsWith("linux"); at the beginning and return that here?

Also, anyone have thoughts on making this public means we should instead return an enum of LINUX, WINDOWS, MAC_OS_X, OTHER?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, how about replacing isLinux() with the following method?

private static final OsType OS_TYPE;

static {
    // ... Detect OS type here ...
    OS_TYPE = ...;
}

public static OsType osType() {
    return OS_TYPE;
}

OsType could look like:

public enum OsType {
    LINUX,
    WINDOWS,
    // MAC_OS_X, FREEBSD, ... (Do we need them?)
    OTHERS
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK 😄 I understand.
I modified with reference to comment.

Copy link
Member

@trustin trustin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It getting a little bit more effort than expected but I guess it will be useful to have SystemInfo.osType(). PTAL, @mumgmangmange.

/**
* Return whether Linux is used.
*/
public static boolean isLinux() {
return Ascii.toLowerCase(System.getProperty("os.name", "")).startsWith("linux");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, how about replacing isLinux() with the following method?

private static final OsType OS_TYPE;

static {
    // ... Detect OS type here ...
    OS_TYPE = ...;
}

public static OsType osType() {
    return OS_TYPE;
}

OsType could look like:

public enum OsType {
    LINUX,
    WINDOWS,
    // MAC_OS_X, FREEBSD, ... (Do we need them?)
    OTHERS
}

Copy link
Member

@trustin trustin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, meant to request changes. Sorry. 😅

Copy link
Contributor

@codefromthecrypt codefromthecrypt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe too much for this PR, but I would love to see a "Platform" like type that does the detection of things like this in a lazy way.

https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/internal/platform/Platform.kt#L199

If single dimension doesn't cover parts we need..
Platform.get().isOpenSslAvailable()

We could instead do it like this..
Platform.get().os().isOpenSslAvailable() where the .os() looks deeper at the OS type and also caches it.

Don't let that slow this work, though (pun intended).

@codefromthecrypt
Copy link
Contributor

fyi this inspired me to notice and fix some things in brave. thanks! openzipkin/brave#1006

if (useOpenSsl != null) {
return useOpenSsl;
}
useOpenSsl = getBoolean("useOpenSsl", OpenSsl.isAvailable(), value -> OpenSsl.isAvailable() || !value);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can avoid isAvailable if the user explicitly disabled OpenSSL.

final boolean useOpenSsl = getBoolean("useOpenSsl", true);
if (!useOpenSsl) {
  // OpenSSL explicitly disabled
  return Flags.useOpenSsl = false;
}
if (!OpenSsl.isAvailable(){ 
  ...
} else {
  ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this useOpenSsl variable unconditionally true?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, true is the default value unless a user sets com.linecorp.armeria.useOpenSsl=false.

At least I think it is let me know if I missed something :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I understand 😃

@@ -109,6 +111,12 @@
JETTY_ALPN_OPTIONAL_OR_AVAILABLE = false;
}
}

try {
osType = OsType.valueOf(Ascii.toUpperCase(System.getProperty("os.name", "").split(" ")[0]));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OS detection is a bit more complicated unfortunately.

Can you use the if statements for the OsType OS's from this famous OS detection logic?

https://github.com/trustin/os-maven-plugin/blob/master/src/main/java/kr/motd/maven/os/Detector.java#L150

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. 😃 Changed to an if statement.

WINDOWS,
LINUX,
MAC,
FREEBSD,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would lean towards leaving out FREEBSD and SOLARIS - it's unlikely Armeria servers would have logic specific to them anyways so they can go in OTHERS

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. 😄
I thought FREEBSD and SOLARIS as OTHERS and changed it.

Copy link
Contributor

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just left some nits. 😄

@@ -422,7 +403,30 @@ public static boolean useEpoll() {
* {@code -Dcom.linecorp.armeria.useOpenSsl=false} JVM option to disable it.
*/
public static boolean useOpenSsl() {
return USE_OPENSSL;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need the null check that returns the value after we set it once like we had before (can use a different name for the local variable if it makes it confusing).

core/src/main/java/com/linecorp/armeria/common/Flags.java Outdated Show resolved Hide resolved
core/src/main/java/com/linecorp/armeria/common/Flags.java Outdated Show resolved Hide resolved
Copy link
Collaborator

@anuraaga anuraaga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Copy link
Contributor

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot @mumgmangmange! 👍

Copy link
Member

@trustin trustin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you move OsType to top level? LGTM except that.

Copy link
Contributor

@ikhoon ikhoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mumgmangmange Thanks for your long efforts! LGTM please address @trustin review.

@minwoox
Copy link
Contributor

minwoox commented Oct 25, 2019

@anuraaga, any other comments?

@codecov
Copy link

codecov bot commented Oct 25, 2019

Codecov Report

Merging #2184 into master will increase coverage by 0.05%.
The diff coverage is 32.5%.

Impacted file tree graph

@@             Coverage Diff             @@
##             master   #2184      +/-   ##
===========================================
+ Coverage     73.64%   73.7%   +0.05%     
- Complexity     9620    9635      +15     
===========================================
  Files           839     840       +1     
  Lines         37022   37041      +19     
  Branches       4561    4566       +5     
===========================================
+ Hits          27266   27302      +36     
+ Misses         7432    7408      -24     
- Partials       2324    2331       +7
Impacted Files Coverage Δ Complexity Δ
...ava/com/linecorp/armeria/server/ServerBuilder.java 74.54% <0%> (ø) 106 <0> (ø) ⬇️
.../java/com/linecorp/armeria/common/util/OsType.java 100% <100%> (ø) 1 <1> (?)
...a/com/linecorp/armeria/common/util/SystemInfo.java 25.46% <20%> (-0.85%) 6 <1> (ø)
...c/main/java/com/linecorp/armeria/common/Flags.java 61.03% <25%> (-0.64%) 54 <3> (+1)
...inecorp/armeria/server/grpc/ArmeriaServerCall.java 87.1% <0%> (-0.4%) 85% <0%> (-1%)
...ecorp/armeria/spring/ArmeriaAutoConfiguration.java 80.43% <0%> (+0.43%) 11% <0%> (+1%) ⬆️
...a/common/grpc/protocol/ArmeriaMessageDeframer.java 72.81% <0%> (+0.48%) 49% <0%> (+1%) ⬆️
...com/linecorp/armeria/server/HttpServerHandler.java 82.05% <0%> (+0.66%) 83% <0%> (+1%) ⬆️
.../linecorp/armeria/client/Http2ResponseDecoder.java 61.66% <0%> (+0.83%) 33% <0%> (+1%) ⬆️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 610e29e...8bac05c. Read the comment docs.

@minwoox
Copy link
Contributor

minwoox commented Oct 25, 2019

@mumgmangmange Could you sign the CLA so that we can merge this PR?

@minwoox minwoox merged commit 5eb5ac3 into line:master Oct 25, 2019
@minwoox
Copy link
Contributor

minwoox commented Oct 25, 2019

congratulations on your first PR, @mumgmangmange!
Thank you~! and Thanks, reviewers!

eugene70 pushed a commit to eugene70/armeria that referenced this pull request Nov 10, 2019
Motivation:
Related line#1645
`useOpenSsl` in `Flags` is used only when TLS is enabled. However, it takes a lot to instantiate `OpenSsl` class so it adds up a tremendous time to the server startup time. We should fix to instantiate it only when it needs.

Modification:
- Set `useOpenSsl` in `Flags` lazily
- Check whether the OS is Linux before calling `Epoll.isAvailable()`
- Add `OsType`

Result:
- Reduced server startup time to 80 percent (20% decreased)
fmguerreiro pushed a commit to fmguerreiro/armeria that referenced this pull request Sep 19, 2020
Motivation:
Related line#1645
`useOpenSsl` in `Flags` is used only when TLS is enabled. However, it takes a lot to instantiate `OpenSsl` class so it adds up a tremendous time to the server startup time. We should fix to instantiate it only when it needs.

Modification:
- Set `useOpenSsl` in `Flags` lazily
- Check whether the OS is Linux before calling `Epoll.isAvailable()`
- Add `OsType`

Result:
- Reduced server startup time to 80 percent (20% decreased)
@ikhoon ikhoon mentioned this pull request Oct 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants