On the eBay developer platform, there are four application frameworks that are used to develop applications– V3, Raptor, Raptor.io and Node.js. V3, the oldest framework, has been part of eBay for more than fifteen years. Raptor and Raptor.io are the latest offering based on Spring and Spring Boot. eBay has made tremendous progress in rewriting hundreds of applications from proprietary frameworks to Open source Spring and Spring Boot. But a couple of hundred applications that are largely in maintenance remain and still use the V3 framework to serve public traffic. The diagram below shows the V3 platform ecosystem.
As illustrated in the diagram above, there are five flavors of applications in V3:
● V3 SOA is a services stack based on SOAP
● V3 Trading and Shopping are a service stack based on Axis, and mainly serves APIs for 3rd party developers of eBay
● V3 BES is a messaging stack built on a relational database
● V3 XSL/V4 Pres is a web stack for the presentation layer
● V3 Batch is a batch stack for offline processing
All legacy applications are deployed on a vendor supported technical stack (JDK, container and OS) that is fast approaching their End-of-Life. This has created a sense of urgency to move all legacy applications out of these vendor supported stack. The preferred destination at eBay is an Open Source based Raptor and Raptor.io that deploys applications on OpenJDK, Tomcat and Ubuntu.
In order to facilitate a low cost migration from vendor supported tech stack to the Open source, we developed a tooling platform that is described in this document. This platform enables a central team to move the applications from the old environment to the new. Project structure, build systems, application packaging, deployment to the new environment are all taken care of by this central team using tooling. The application team is involved only in validation and the actual traffic migration. We call this approach “forklifting” because the application code is literally “forklifted” by a tool from the legacy to the new frameworks. Note that with this approach the application code is not changed. This was acceptable since our primary objective was to eliminate vendor supported software without an immense cost of a rewrite to application teams.
Our first challenge was to make the migrated code work as it had before, and here’s how we did it.
The following diagram shows the architecture after migrating to Raptor/Raptor.io.
As mentioned earlier, we are not aiming to refactor or change the code of legacy applications. The code had to work as is in the new environment. Legacy applications run on legacy frameworks. This meant that we had to support these legacy application frameworks in our latest deployment environments.
The main two tasks were:
SOA/Trading/Shopping frameworks were ported to the Raptor.io framework and is available as a Spring Boot component
Batch/BES frameworks were ported to the Raptor framework
Approach and Design
To build a migration tool, we first needed to identify the common patterns and the many differences between V3 and Raptor/Raptor.io. For each individual application’s migration, we considered two perspectives: resources and runtime.
● Code structure
● App metadata, captured in proprietary XML files such as raptor_app.xml, etc.
● Application configuration
● Dependency changes (i.e. deploying on OpenJDK, Tomcat and Ubuntu may have different behaviors.)
● Stack specific architecture differences (e.g. Ratelimiter is a local call in legacy stack, but a remote call in Raptor.io.)
● Stack library backward compatibility (e.g. V3 Batch is an eBay proprietary batch framework, while Raptor batch is based on Spring batch)
● Framework library backward compatibility (e.g. Raptor.IO rewrites the library to components and some classes' signatures are changed)
● Third-party library backward compatibility (e.g. Jersey version is 1.x in V3 and Jersey version is 2.x in Raptor.IO)
● Initialization mechanism difference (e.g. V3 is a proprietary initialization mechanism but Raptor IO uses Spring boot initialization)
● Instance Lifecycle (e.g. Instance construction time point is different between the v3 container and Spring Boot container of Raptor.io)
● Unexpected exceptions (e.g. same class from different libraries has different implementations)
After we had a detailed breakdown, we categorized them into three levels:
1. Framework level problems
● Code structure
● App metadata
● App configuration
● Framework kernel library backward compatibility
● Third-party library backward compatibility
● Instance lifecycle
● Dependency changes
2. Stack level problems
● Stack architecture differences
● Stack library backward compatibility
3. Unplanned discoveries
● Unexpected exception
Based on the above analysis, we created the following architecture for our migration tool platform.
There are two platform converters – one is for Raptor, and the other is for Raptor.io. Platform converters offer the lower level framework backward compatible layer. For stack level differences, we offer a plug-in to handle the differences. With this design, all the common problems are pushed down and handled by a central migration team, instead of training each application team to understand all nuances of the migration. The bulk of the work involved in the migration can be performed by a few team members who are able leverage the following :
- Built up expertise and a shared knowledge base as they tackle one application after another
- Similar methodology to handle problems arising in different stacks.
Implementation Case Study
There are eight logical components in the platform converter. Let us look at the code structure as an example.
V3 code structure was designed as a composite of applications. A deliverable in V3 is a binary package that is deployed to a cluster of machines in various environments such as staging, production, sandbox. A deliverable may consist of multiple applications produced by different teams or just one application produced by one team. On the flip side, a given application can be part of multiple deliverables. Below is an illustration:
Therefore, the implementation needed to satisfy the following:
Combination requirement: For some Trading/Shopping deliverables, a requirement was for all applications of one deliverable to be part of a single Raptor/Raptor.io application. We needed to modify our tool strategy to accommodate this case.
Separation requirement: Some deliverables had strong requirements to be split into different applications.
Mixed application requirement: Some deliverables contain a mix of applications of different types (e.g. V3 SOA, Trading etc).
To meet all the requirements, we needed to refine our solution. The applications of the deliverable were separated into two types. Applications that exist only in one deliverable were called non-shared applications. Applications that were included in many deliverables were called shared applications. The tooling supports parameters like “-services” “-sharedservices” to handle these various scenarios.
The migration tool platform has maximum flexibility at the design level due to the following code structures:
We implemented five stack plugins in this tool platform – Batch Plugin is described below.
V3 batch is based on a proprietary batch framework, while the target, Raptor batch, is based on Spring batch. Needless to say, there are significant differences. For example, the V3 batch task class is a Java class called Task, while the Raptor batch task class is a Java interface called Tasklet. Batch Stack Plugin had to bridge these differences to minimize application code changes.
The main objective of migration is to maintain the customer's business logic code. Batch stack plugin overcomes the difference and makes the existing code work as is.
From the design pattern perspective, this is solved using the Adapter pattern, so that the application’s business code does not need to change. The migration team needed to build an adapter library. Therefore, the whole V3 batch core classes were considered as APIs, and class signatures were kept as before. It was reimplemented again using Spring Batch. It required the migration team to have thorough knowledge of the classes, lifecycle and initialization difference in V3 and Raptor batch core.
Each stack of the framework has its features. The migration team had to take the following actions:
- For features that behave differently, we used the same behavior as V3, but reimplemented the feature in Raptor Batch.
- In the case where some features were supported in V3, but retired in Raptor, like DSF and ESF, different strategies were applied.
- In batch, all the run-time logic associated with DSF/ESF were email functions. Since the email team already offered replacements, the migration team offered a detailed solution to help migrate the function.
- During the initialization, some ESF and DSF initialization modules were called by transitive dependency, but they did not interfere with the business logic. The team made configuration or code changes to bypass this kind of module.
We introduced the main design concepts for the two cases above. With this tool platform, code migration was no longer the long pole for the V3 migration project. Any application can be migrated within two minutes, and the migrated application is ready for testing on staging in about one day after the migration team fixes common problems.
The framework level migration is a brand new methodology, which currently benefits V3 migration projects but also provides a reference for any future framework migration. This approach offers the following advantages
First and foremost, it solved the key objective of the V3 migration program, which was to eliminate EOL vendor software at eBay.
Shielded consumers of the forklifted apps from having to make changes due to a replatforming of the service that they are consuming
Modernized the toolset (IDE, Project structure, build systems) of the forklifted code, which makes refactoring of the code more efficient in the future. (Note: forklift does not touch the legacy application Java code)
All of this was achieved with minimal involvement of the application teams that owned the application.