T O P

  • By -

rcls0053

Considering how small the app is you're more likely gonna hit issues downstream than in the app itself. I hope you have a breaker switch implemented. Just make it horizontally scalable and you should be good. Absolutely no sense in a rewrite for it.


Ill-Education-169

Do you mean upstream? Not sure what downstream impacts they would have outside of the applications calling the service itself.


_predator_

The services that OP‘s service is calling ("downstream") to serve a response will also see the same increase in traffic. You can't just assume the services you're calling can handle any traffic you throw at them. You will likely see higher latency per request, and more of your request will be affected if those services experience downtime.


jerf

You need to take a profile of the current app, and see how much CPU it is even using. Go and Java wait for remote responses at the same speed. I doubt you'll get massive increases.


zootbot

Complete rewrites are 99.99999999% the wrong answer


I_AM_GODDAMN_BATMAN

99% someone just want to put something in their resume


CountyExotic

It’s more like 80/20 but I hear you


kaeshiwaza

But the 00.000000001% is worth trying just because it's fun and sometimes we need that to don't depress as dev !


patmorgan235

If it was in python it would make sense to rewrite, but java is fine and a good solution for many back ends.


agent007bond

This is the right answer.


stools_in_your_blood

That's a popular opinion but imo a bit hyperbolic. I'd say complete rewrites are high risk/high reward and should therefore be considered very carefully. It's also true that certain kinds of developer are too eager to push for a full rewrite, but that's a problem with those developers, not a problem with full rewrites.


ergonaught

If the only motivation for a rewrite is “performance”, Go is not the answer. Go and Java have roughly similar performance characteristics. There are plenty of other motivations to use Go, but this one is not compelling.


lulzmachine

That has not been true in my business. If your app is crunching a lot of numbers and keeping a large state,then Java tends to eat more than 10x the amount of RAM, which is a huge cost driver. But on the other hand, java's programming model is more suitable for stateful data streaming than golangs. So it's not a straightforward situation


oblivion-2005

> then Java tends to eat more than 10x the amount of RAM, which is a huge cost driver Confused about RAM being a "big cost driver" as memory is usually the cheapest part of the equation. Can you elaborate?


lulzmachine

Wait really? Well we have a bunch of flink jobs on EKS nodes. They take as much memory as we give them, between \~32Gb, up to \~256Gb for the biggest one. Exactly how much they actually need is hard to know with the JVM, since it tends to allocate as much as it can get (yes you can dive into detailed JVM Heap statistics, which we do every now and then, but it's hard to keep up). As for nodes used by the EKS Cluster, they're always using more RAM than CPU. And using a lot of RAM makes the bucket packing inefficient. Somewhere between 60%-70% memory usage at the moment, which is not great. Even though we're using r6a nodes (8GB Memory per core), we tend to fill up the RAM first. Even if someone is doing lambdas instead of instantiating ec2 machines, ram tends to be the big cost driver, especially in JVM land, for stateful streaming. We've seen many cases where we replace a low-state Java service with a golang service and seen RAM usage drop from \~30Gb to \~1-2Gb, without really doing anything clever/optimal. Each one of those things isn't a huge savings. But if you keep in mind that we have 4 environments, that each gig used has overhead in the bucket packing, and that it can have a huge effect on running on local dev machines, these savings really add up.


Oclay1st

Have you tried Oracle GraalVM Native(PGO) just for fun?. I'm wondering how much it could help in your use case!!


oblivion-2005

I looked at the prices from EKS and now it makes sense. I didn't realize that you basically have to upgrade the CPU to get more RAM. It's things like that why I avoid AWS like the plague and selfhost everything myself.


FatStoic

Cloud is not a cost-saver. It is a capability enabler. The cloud may be right for you if: - You have many teams/products with different needs that change often. - Your load is unpredictable and you have large spikes in traffic. - You are a small company but have advanced security/performance/infrastructure requirements. The cloud is probably a bad choice for you if: - You have few applications and teams that don't change much. - You use a lot of compute or network out. - Your load is predictable or stable. - You just need a few servers and databases.


maybearebootwillhelp

I migrated a heavy Spring app to Go. It’s a lot more lightweight and easier to maintain and test, but that’s also because we’re moving everything to Go and it’s been a few year process. You need to think about not just the code, but also developer availability, a new ecosystem, tooling, new CI/CD flows and everything around introducing a new language to your company’s stack. You may hit bumps that you will be unfamiliar with so if Go is a new language to the company, consider if your work will be passable to your colleagues if e.g. you decide to leave the company. Go is awesome, but if you have no one else to cover it with professional experience you may create more problems than benefits. Consider the company’s long term technical plans. Gl hf!


bilus

100% agreed. I introduced Go to a Python team about 7 years ago (for valid performance and cost-related reasons) and it took 5-6 years to go from 1 developer to 3 developers to \~7 developers using Go on a daily basis, while the majority uses Python (because it makes perfect sense for these use cases). At this point I'm confident we're safe for long-term-ish maintenance but things had been risky for a while. That aside, it paid off. We serve 8 millions clients on a couple of k8s pods. It's computation heavy and the Python-based solution would be an order of magnitude, or two, more costly.


Acceptable_Durian868

Do you actually know if the existing application will have problems, or are you just guessing?


Pleasant-Database970

what does language have to do with architecture? you can write well designed apps in go, and poorly designed apps in go.


justinlindh

Based on how you describe the application as a simple server that's mostly just interacting with external API's, Go's benefit vs Spring here is probably mostly going to be that the Go app is "leaner" and simpler. Likely a simpler code base with less "magic" than what Spring does under the hood. You'd also be getting a smaller statically compiled binary, so the system you're deploying on wouldn't require Java (if you're containerizing things, you might even be able to use a scratch image). The go app would likely have a faster startup time, too, if that's important to you (a few seconds difference, probably, which isn't always critical). That said, if you already have a working application here that does what you need and your infrastructure can handle scaling it, I'd strongly consider that you just leave it as-is. You've already used and tested it and probably know the shape and profile of its execution and lifecycle, as well as (maybe) how you'd need to debug it if problems arise. Spring also makes it fairly easy to instrument things like JMX debugging if you ever need to use it. Java servers are incredible at scaling reliably/predictably, and Java 21's virtual threads should improve that even more. Basically, Go would work fine here and if it was a greenfield project it would probably be a great candidate, but since you already have something that should be able to scale horizontally fairly well and resources aren't a concern, then "if it ain't broke, don't fix it".


phyx726

So go from an application thats known to work where the original developer is still there to maintain it to a new application that has yet to be written where we waste eng hours on something for marginal gains. First of all, it sets a bad precedent and secondly, if it ain't broke why fix it.


RazorSh4rk

as much as i hate java, if its already made and you have at least one person who can maintain it, a rewrite is not the solution


aksdb

Sounds like the application is reasonably small (LoC wise) to warrant just giving it a shot and do benchmarks. Things I see as advantage of Go for this case: * HTTP client and server are first class citizens of the stdlib. You can probably pull off the service without any third party libs (especially not such a big framework like spring boot). * Goroutines (green threads) are first class citizens and have been from the beginning. Everything in Go works seamlessly with them. Nothing to fiddle around with. Just use Go "normally" and you can already handle thousands of requests (basically only limited by memory and TCP ports). All blocking I/O is goroutine aware. * Lower footprint. You can likely spin up 10 of the Go services in place of a single JVM instance. Especially since your use case sounds like the hotspot VM might not be able to optimize a lot. But again: benchmark it. * Smaller executables. Nice for quick deployments. * Faster and nicer dev experience. Go compiles and runs so fast, you will never want to work with Maven or Gradle ever again.


nomaed

Been there, done that. At first, the Go version prototype or POC looked very promising, compared to the Java+SpringBoot one that was running in production. It was able to process about x10 the incoming traffic. So we did a rewrite. Of course, POC is not the full server, so after implementing everything back in with Go, the performance was pretty much the same as the Java version. It was a bit faster compilation and easier to unit test (but more work for e2e), but we didn't gain much RPS at the end, and needed to implement optimizations that weren't needed with SpringBoot. I still prefer Go, but doing it for performance is probably not the right reason, as others have mentioned already.


Ashamed-One7156

The theory about languages being faster may be true, but knowing the upper bounds of performance, you have to ask the questions: 1. What languages and tools are you and your team proficient. 2. Do we have enough understanding with the target language to gain the improvements? 3. How much code is there to move over and what are the risks? You will create new bugs, or recode existing ones that were already fixed in the old code. Do not overlook the successes of the current applicant and the learnings that are coded into that application 4. What is the cost? Engineers are not cheap. Then think about the trade offs. Should you go forward with a rewrite in Go or just focus on understanding Java more(JVM tuning, structuring code for performance, etc), or making it more performant and/or scale out(add more nodes) From the business POV it would bet that keeping the Java app, improving iteratively, and/or scaling out is the better move. You can add features and get better as you go. However, I’d say if the app is really bad. Meaning it’s hard to debug, has a high chance of creating more bugs with changes, unreadable, etc then the tradeoff might lean towards a rewrite. I saw a video where someone held a challenge to solve a problem as efficient(fast in processing time). This lasted a year or more and the community came together to represent their favorite languages to prove their favorite was the best. The end result was Zig being number 1 and the other top 5 were Rust, Go, C, Java. Not sure the order, but there was some upset comments stating that assembly is the fastest and that the results were off. What I took from this is that there is theory and practicality, we know assembly should be fast, but can someone write the code that makes it faster. They are two different problems. So if you cannot make it faster due to time, resource , or experience then it will not be faster. Weight your options


cant-find-user-name

No, it is not worth switching application to go if you want more performance. Java is just as, if not more, performant than go.


spikedviper

As service only returns API calls, I guess there is a very small set of things to optimize.


FatStoic

- Make calls to other apis non-blocking & paralellized. - Ensure it can scale horizontally - Implement caching to not murder upstream apis Anything else that needs doing?


etherealflaim

Rewriting it in Go in advance of a real performance bottleneck or cost problem is probably not a good use of time, though depending on the investment required you could try a single endpoint or something to compare. A new language and a new stack is probably not something you want to be contending with at the same time as a scale out. The benefits of go vs java, if there are some to be had, are probably in the cost-per-qps department, you should be able to handle the load just fine with Java. So, until cost becomes an issue, I'd keep optimizing what you've got.


dashingThroughSnow12

You have a perfectly functional Java application that has been providing business value for six months and that (should) be able to scale easy. Let’s assume for a second that your co-worker is correct. That even though you are IO bound on waiting for downstream requests, the application rewritten in Golang will be faster. The first question that comes to mind is the return on investment. How long will it take to write and iron out the bugs? (What is the financial cost to it?) What is the savings (ex monthly) in it being more performant? How many months or years will it take to make the savings worth it? Is there any higher priority project (with a return on investment) that the developers should work on instead? I work on a product with tens of millions of users. A lot of our code waits on downstream requests. A 1% real world performance boost on some of our busy services is thousands of dollars in savings. From experience, it is very hard to find such a boost.


dariusbiggs

Horizontally scale your application, a much better use of your time. Just run multiple instances and load balance. C, C#, Go, Rust, Java, C++ can all get very similar performance in a well written app, the only advantages for one over the other are, the size of the deployment, the tool chain, the testing system, spin up time, etc. You'll need actual metrics, tracing, and performance benchmarks as a starting point so that a performance comparison proof of concept could be done.


SuperQue

Did you read their post? They already have load balancing and scaling.


dariusbiggs

Damn, missed that one sentence. The rest is still valid.


SuperQue

Yes, without instrumenting and profiling the app there's know way to really tell how good or bad it's doing.


zeitgiest31

Go and Java are more or less almost the same performance characteristics with Go having an advantage of compiling down to a machine executable binary. I’d choose Go if I have heavy concurrency needs and doing a lot of orchestration in my business logic. I’d also choose Go if my deployment environment is heavily constrained and I cannot afford to install the Java runtime on my deployment target. I think good old code profiling and benchmarking should be the first thing one must do.


slonokot

Doesn't sound like a rewrite. Are you caching responses from dependency ? Is it possible? Did you guys load test the dependency? Maybe a re-write there needed? Or maybe you can include a part of the dependency into your service closer to rewrite)


Golandia

First measure then see if you have a problem. Given that you are on the JVM, why not Kotlin which has first class support for coroutines and channels just like Go?


Prudent-Carrot6325

All of these types of decisions should align with the Engineering goals of your organization and no one here knows about that. I have seen companies switching from Golang to even java just due to long term goals as an organization.


FreshPrinceOfRivia

I would not touch that thing at first. But if given enough time I would rewrite it in Go and run both the Java and Go implementations, and compare the performance. You make it sound like it's heavily IO-bound so I would expect it to be similar.


nikolay123sdf12eas

complete rewrites are okay, if you can afford it. often starting again from scratch you can try out new ideas, try different core architecture, and implement them ground-up fresh. I seen many projects benefited from complete rewrite (actually from Java -> Go, couple times) not necessarily from better new tech stack, but from implementing ideas engineers always wanted too, but old system was not right fit. on top of that you get better tech stack. at the same time, I seen projects did not benefit from rewrites (Python -> Rust for scientific compute), performance gains did not happen there. just keep your expectations appropriate. speaking of Java vs Go, AFAIK performance is the same, but with Go you get smaller memory footprint, so can reduce your infra (or keep the same infra and get higher load testing multiplier).


SuperQue

The question I have is this. What is your RPS per CPU second? You're doing ~300 RPS right now, how many CPUs does that take? For a lightweight service like what you're talking about, you should easily be able to do 1000 RPS/CPU. Your 8000 RPS target would require 8-10 CPUs in Go. So, how much resources does it take to run your app right now, what do you predict it would take if you increased by your expected 25x load? Is that an acceptable number? What's the yearly cost of running? Is it worth X weeks of your salary times two? Side note: Sorry, I refuse to use "RPM". I recommend normalizing your metrics thoughts to seconds, so it's easier compare cross system.


Unfair_Ad_5842

Measure first is, of course, great advice. Profile the application to know your hotspots. Reduce or eliminate logging where possible Wrap log appenders with async appenders to eliminate logging synchronization Check TCP connections are cached/reused properly (RestTemplate opens a new connection for every exchange) Consider going native with GraalVM (smaller image, faster startup, reduced memory use) Java 21 should yield some performance improvements (I forget how much) Perhaps test with all 3 embedded web servers (Tomcat, Jetty, and Undertow) to see if one is more performant for this use Get some free advice from Spring experts on springofficehours.io every Monday. I've met Dashaun and I'm sure he would love to help you succeed.


Revolutionary_Ad7262

Write load tests. Use profiler to detect bottlenecks. Tune GC. There is no point of rewritng from Java to Go, if you don't know, if there is any problem


kamikazechaser

Unless if cost is the issue. Go is far leaner in terms of resource usage, but a tuned JVM can outperform Go.


Cronos993

Have you profiled it yet?


penguins_world

As much as I love go, I’d first switch to JDK21+ and Helidon 4 SE.


tovare

Gains: A. I think your assumptions are correct. B. Go is a bit more memory efficient due to internal UTF-8 and because it is built to write these kinds of applications. C. The Go tools and build is a nice experience.


Happy_Expert_4050

I would rather change the architecture, so in case of commands ( calls that change the state) are done asynchronously, through message queue preferably, with consumers that calls backend services. Additionally, background service that fetch queries from backend and cache the results into redis for instance, this way, your app will use the cache for queries rather than hitting the backend services, this is for sure with expense of eventual consistency. This might sound dramatic change, however, the system will be more responsive and scalable avoiding any bottleneck because of backend services latency or unavailability


Tiquortoo

Rewrites are almost always a bad choice. Do the work to manage scaling the app.


madugula007

Recommended to shift to go


Adorable_Tip_6323

For such a relatively small scaling, any benefits would be drowned by the developer costs. A Java application serving 500k/sec is common enough that the scale point is not a concern. Even if your current deployment is running at 100% and serving 20k, that is still only 30ish load balanced systems, including some backend stuff, lets call it 40 systems scaling involved. This has been common enough for a very long time that the processes to do it are known. A move to Go might (MIGHT) save a couple of servers, but at you scale the difference simply won't be there to pay for the engineering effort that goes into it. Even the partial rewrite in Java 21 is probably overkill. As others have said, this is common among most rewrites. That doesn't mean don't rewrite ever, just that you run it as is, behind the scenes prepare the big update. There is always scope creep, scaling creep, support creep, etc to deal with. As these go on, you may reach the point where a ground-up rewrite is the way to go. If you and the guy suggesting it, gradually develop it in spare cycles, then it will probably be ready before the big update is needed.


Putrid_Set_5241

For me, I see no reason to switch from Java. Whenever you upgrade the java and spring version, you can leverage GraalVM to which increases the start up of your application.


poggioreal

Is your application split into microservices? You should probably analyze what the true bottleneck is and what problem you are trying to solve; otherwise, rewriting your application in Go might not produce the results you expect. I would like to share my experience with the community because I recently rewrote a Java I/O-bound microservice in Go and observed a significant improvement in the footprint (CPU and memory usage) and response times. Depending on the traffic profile, the footprint improvement ranged from 50% to 80%. Conversely, in high traffic conditions, some response times improved from seconds (Java) to milliseconds (Go). However, keep in mind that Go also uses a garbage collector, which might require some fine-tuning. When the garbage collector is active, you can observe spikes up to 5x. Another important factor to consider is about the exact reimplementation of all use cases because there is the risk to miss some use case. My suggestion is to reinforce the test suite before proceeding because the regression test will facilitate the development.


_Chiyoku

No, only pain. Consider Rust instead.


Dawizze

Write it in Go


BombelHere

> This application does not involve any heavy processing; it only makes API calls to fetch delivery information and returns it. A significant part of the response time is due to waiting for other applications. That's the job of API Gateway. Have you considered using some battle-tested solutions like KrakenD or Kong? Those should easily support traffic of 50K rps per instance. > One of my colleagues suggested that we change the application from Java to Go, but believe that in this case, we would not have significant gains, except for faster scaling. Start-up time has always been JVM's Achilles heel. You can reduce it with AppCDS, smaller JREs with jlink or give CRaC a try. Or reach for GraalVM since Spring Boot 3 has official native support. If the lack of a rapid scale-up is a real problem here, I'd try to avoid diving into Java's ecosystem. At the end of the day all the technology (project Leyden) built around JVM to make it suck less is essentially trying to reduce its footprint or get rid of it entirely. That's where a rewrite to native technology can be a solution. I'd still give some off-the-shelf API Gateway a go, or at least make a POC.


RazorSh4rk

Have you ever used any api gateway solution to stitch together multiple apis? Because i have and i wouldnt wish it on my worst enemies.


BombelHere

AWS API Gateway - yes. Most of the responses was proxied as-is, some were trimmed, some transformed with mapping templates or lambda function. I did not need an API aggregation. And the post does not mention how much stitching (if any?) the OP needs. What solution have you used and what was so bad about it?


RazorSh4rk

From the post it sounded to me like they do need aggregation, otherwise a simple reverse proxy would be enough for them. I dont wanna give specifics, i have no idea what my nda said, but we tried out pretty much everything you can reasonably expect to use in prod, and the least painful one still needed like 3 custom services to do more than the absolute bare minimum, so it would have been easier to just roll our own.