[HN Gopher] Continuous delivery makes JVM JIT an anti-pattern
___________________________________________________________________
Continuous delivery makes JVM JIT an anti-pattern
Author : foxgrover
Score : 20 points
Date : 2021-02-01 17:11 UTC (5 hours ago)
(HTM) web link (blog.astradot.com)
(TXT) w3m dump (blog.astradot.com)
| lazide wrote:
| Every serious Java based Web App I've ever worked on had a
| prewarm step or continuous probing setup for exactly these
| issues. It isn't unique to Java either - lots of languages have
| lazy library or dependency loading, or runtime caching of
| external files or the like that you want to do before you start
| serving requests.
| kimi wrote:
| Or a cache to be loaded. In related news, "Continuous delivery
| makes caching an anti-pattern".
| p2t2p wrote:
| Not really. You move cache off-heap in Java terms and it
| persists it between restarts. One Russian social network has
| about 60 gigabytes of stuff cached that way
| ncmncm wrote:
| This is about runtime binding vs static binding, not static
| objects or static members. There is still a "this", but the code
| that will run is known up front -- "ahead of time".
|
| C++ went through this 25+ years ago: runtime binding, what in C++
| is virtual functions, is a _niche technique_. Most C++ programs
| don 't use it at all, or use it in only one or two spots. When it
| is the right thing, it makes the work convenient, but it really
| is just a dance with function pointers. In C++, templates do the
| heavy lifting.
|
| Java never offered any other support for organizing programs, so
| inheritance and virtual functions have been your go-to for
| everything, no matter how bad the fit. In a static call there is
| only one bit of code to run, and it never changes over the life
| of the program. Just like _almost everything_ , really, except
| here your runtime knows up front.
|
| It was always a dumb choice to make member functions default to
| virtual semantics, when they almost always don't need it, and it
| just costs performance to no purpose. That is what comes out of
| treating language design as a marketing exercise: Java's
| designers really (and openly) cared less than nothing about
| object-oriented programming. They thought people really ought to
| be coding Lisp. Forcing runtime binding was a way to sneak in
| something a little bit lispy, and maybe get people used to
| production code running no faster than Lisp.
| tom_mellior wrote:
| > It was always a dumb choice to make member functions default
| to virtual semantics, when they almost always don't need it,
| and it just costs performance to no purpose.
|
| If you _actually_ don 't need it (i. e., your hot methods are
| never overridden), then the JIT will trivially compile those
| "virtual" method calls as non-virtual ones. It has all the
| information it needs, since it knows what classes are loaded.
| It can invalidate its code if necessary, if you load more
| classes that do add overrides. So no, it does not cost
| performance at the call site. It does cause the compiler to do
| work, but nothing fancy.
| astrange wrote:
| Java is based on Objective-C, which is based on Smalltalk. In
| both of those all method calls are messages, which are even
| more abstract than virtual functions but a lot more useful.
|
| Java simplified things for performance but ended up with a much
| weaker and less expressive system, and probably didn't go hard
| enough for static performance either. Still, it's less of a
| performance issue than the lack of value types.
| filereaper wrote:
| >Molding a 25 year old runtime ecosystem to adapt to AOT
| compilation feels like putting lipstick on a pig.
|
| Other JVMs like J9 have had AOT support for decades now, its not
| "lipstick on a pig". There's plenty of material from previous
| JVMLS meetups about AOT.
| olliej wrote:
| Others have raised good points, but seriously something is wrong
| if you're pushing updates that require restarts every hour.
|
| I get the idea of "continuous deployment", but this is sounding
| like restart-per-commit. At that point I question how much
| qualification and validation is happening. No one say unit tests,
| they aren't sufficient, and I've worked on multiple projects
| where the pre-commit test suite runs alone can take more than an
| hour. Even with those tests there are semi-regular breakages.
| winrid wrote:
| Bad deployment system. You should do an A/B deployment and warm
| up the services/caches before the switch, so that the
| architecture handles the problem and not the programming
| language/VM.
|
| At FastComments we run our E2E tests on the new instance to JIT
| the app. Before the Jit API calls can take 100ms, and after
| 10-30ms. Still, that is fast enough that most people wouldn't
| notice...
|
| Also, the problem is not Java. Your application probably has way
| too many abstractions for a simple login page.
| commandlinefan wrote:
| > Go and Rust encourage use of static method calls
|
| Not having worked in Go or Rust but having done a lot of work in
| Java and C/C++, I'm curious how this works out in practice. My
| experience with developers who default to static method calls
| rather than objects in Java or C++ is that they also default to
| static (and therefore global) data as well. Of course, you don't
| have to do that: you can pass pre-transaction data structures to
| the static functions and let them operate on them, but that's
| what object-oriented programming is for in the first place.
| remram wrote:
| Rust is not object-oriented.
|
| You can make "virtual method" calls in Rust (dynamic dispatch
| through a "trait object", a vtable). This is explicit though,
| the type will look like `Box<dyn MyInterface>` where Java says
| `MyInterface` (box = object allocate on heap, dyn = virtual
| method calls).
|
| I think you might be misunderstanding what "static method call"
| means: in this context, it means a method which is not
| "virtual" (in C++ parlance), not a method which is "static" (in
| C++ parlance, e.g. not called on an object).
| commandlinefan wrote:
| You're correct, I was assuming that "static" in Rust & Go
| meant the same thing it meant in Java (which is different
| than what it means in C, of course). Thank you for
| clarifying.
| philipkglass wrote:
| The article's "container lifespan" chart shows that 21% of
| containers live less than _10 seconds_ and 54% live <= 5
| minutes. If the base data set has that many very-short-lived
| containers, it's probably not representative of containerized
| persistent services. How many services get CD updates every 10
| seconds?
|
| Indeed, the original Sysdig report that the chart comes from
| makes this case:
|
| https://sysdig.com/blog/sysdig-2019-container-usage-report/
|
| "Many containers need to only live long enough to execute a
| function and then terminate when it's complete. Seconds may seem
| short, but for some processes, it's all that is required. We
| believe the increased use of Kubernetes Jobs that run finite
| tasks like batch jobs contributed to this growth. In fact, we
| expect short lifespans to increase, especially on serverless
| platforms that are well-suited to running short term tasks."
| tom_mellior wrote:
| > Production Java apps also typically run with APM tracing agents
| that rely on runtime bytecode instrumentation. [...] It is easier
| to start afresh with modern compiled languages like Go and Rust.
|
| I wonder how they instrument their Go and Rust programs. If they
| decide not to, maybe it's not that important for the Java version
| of the same code either.
| hctaw wrote:
| > 74% of containers have lifespans <= 1 hour
|
| This sounds like a design flaw in the architecture. You don't
| tear down a house to replace a lightbulb.
| Hallucinaut wrote:
| Nor do you spent 10 hours with a magnifying glass and tweezers
| to attempt to change the filament on a burnt out light.
|
| Which analogy you consider spurious likely depends on what kind
| of theatres of IT war you've been in.
___________________________________________________________________
(page generated 2021-02-01 23:03 UTC)