Listing Service:
From Monolith to Microservices
Taihei Morikuni
Software Engineer (Backend)
Slide 2
Slide 2 text
Software Engineer
Backend
Taihei Morikuni
Slide 3
Slide 3 text
Listing Service:
From Monolithic to Microservices
Slide 4
Slide 4 text
Listing Service
● Microservice for managing the listing function on
Mercari
● This is the first project for transitioning from monolithic
(PHP) to microservices (Go)
● Currently under development for one HTTP endpoint
● Use gRPC for connecting with other microservices
Slide 5
Slide 5 text
Strategy to Transition to Microservices
Split services while
maintaining API
compatibility
Enable independent
development for
each team
● The goal of transitioning to microservices
is not to split the code, but to make a
scalable organization
● Enable Canary Release by maintaining API
compatibility, lowering the risk
Slide 6
Slide 6 text
● Implement only logic related to listings
● Link the portion left in PHP with Webhook
Technological Strategy for Listing Service
● Automated app tests for the existing API app
● Manual checking by the QA team
● AQA team test tools (under development)
Split services while
maintaining API
compatibility
Enable independent
development for
each team
Slide 7
Slide 7 text
Challenges of Transitioning to Microservices
Connecting from GCP to
MySQL at Sakura
Handling
Additions/Modifications
to Features
Splitting of Transactions
Compatibility with PHP
Exceptions
Slide 8
Slide 8 text
Connecting from GCP to MySQL at Sakura
● Share PHP and DB until the transition to microservices has
been completed
● In terms of security, don’t want to make MySQL ports
available externally
Problem
Solution
● Develop the SQL on gRPC service and a Go library
○ In general, handle only CRUD, don’t handle Join and
Transaction
Slide 9
Slide 9 text
Connecting from GCP to MySQL at Sakura
message SelectRequest {
repeated string columns = 1;
string table = 2;
Where where = 3;
...
}
message SelectResponse {
repeated Row rows = 1;
int64 count = 2;
}
Slide 10
Slide 10 text
Connecting from GCP to MySQL at Sakura
req := Select("id", "name", "age").
From("users").
Where(Eq("lang", "ja"), And(Gt("age", "18"))).
OrderBy(ASC("created_at")).
ToRequest()
err := dbClient.Select(ctx, &user, req)
Slide 11
Slide 11 text
Splitting of Transactions
● Updates of items, shipping information,
and analysis data were included in a single transaction
Problem
Solution
● For item data, Item Service (Sakura) will process the transaction
● For data that the user can see, process as much as possible within
the request
● For internal data, aim for asynchronous eventual consistency using
Cloud PubSub
Slide 12
Slide 12 text
Splitting of Transactions
→ Transaction: Unnatural if the item has been listed but there is no transaction
→ Synchronous: Unnatural if no image of the item was included
→ Asynchronous: No shipment until item sold
→ Asynchronous: Customer cannot see the data for analysis
function listing() {
$db->begin();
$item->save();
$photo->save();
$shipping->save();
$analysis->save();
$db->commit();
}
Slide 13
Slide 13 text
Handling Additions/Modifications to Features
● As listing is a core Mercari function, functions will be added and
modified during the transition from PHP to Go
Problem
Solution
● Create an update tracking branch in the PHP repository,
and delete the code transitioned to Go
○ If an update has been made, the code will conflict when
merged
○ Once all of the code disappears the process is
complete
Slide 14
Slide 14 text
Handling Additions/Modifications to Features
function do_something()
{
if (is_x()) {
return 1;
}
return hello();
}
func DoSomething() int {
}
Slide 15
Slide 15 text
function do_something()
{
if (is_x()) {
return 1;
}
return hello();
}
Handling Additions/Modifications to Features
func DoSomething() int {
if IsX() {
return 1
}
}
Slide 16
Slide 16 text
Handling Additions/Modifications to Features
function do_something()
{
if (is_x()) {
return 1;
}
return hello();
}
func DoSomething() int {
if IsX() {
return 1
}
return Hello()
}
Slide 17
Slide 17 text
Handling Additions/Modifications to Features
function do_something()
{
if (is_x() || is_y()) {
return 1;
}
return hello();
}
func DoSomething() int {
if IsX() || IsY() {
return 1
}
return Hello()
}
Merge conflict!!
Slide 18
Slide 18 text
Handling Additions/Modifications to Features
function do_something()
{
if (is_x() || is_y()) {
return 1;
}
additional_process();
return hello();
}
func DoSomething() int {
if IsX() || IsY(){
return 1
}
AdditionalProcess()
return Hello()
}
Not migrated!!
Slide 19
Slide 19 text
Compatibility with PHP Exceptions
● A PHP exception name is included in the API response as
an error code
○ The client is using PHP exception names
○ Must also return the PHP exception names from Go
● A part of the response JSON is different in each type of
exception
● By transitioning to microservices, exceptions are also
distributed out among each service
○ Each service must maintain compatibility with the PHP
exceptions
Problem
Slide 20
Slide 20 text
PHP Exception Compatiblity
Solution
● Develop a shared Go library to maintain compatibility with
PHP exceptions
● Add PHP exception information for handling errors in gRPC
Status.details
● Retrieve the exception information from PHP-compatible
HTTP endpoints, and directly generate the response JSON
Challenges of Transitioning to Microservices
Connecting from GCP to
MySQL at Sakura
Handling
Additions/Modifications
to Features
Splitting of Transactions
Compatibility with PHP
Exceptions
Slide 24
Slide 24 text
Summary
● In order to solve long-term problems (and not increase debt),
we are keeping these issues in mind as we transition to
microservices
● Because this is the first project for transitioning from
monolithic (PHP) to microservices (Go), we haven’t fully
organized our assets, meaning most parts of the process are
difficult
● The pursuit of accuracy, when there is no correct answer,
can be enjoyable
○ Believe in the setup in which I believe!