4
votes

Currently we have some microservice, they have their own database model and migration what provided by GORM Golang package. We have a big old MySQL database which is against the microservices laws, but we can't replace it. Im afraid when the microservices numbers start to growing, we will be lost in the many database model. When I add a new column in a microservice I just type service migrate to the terminal (because there is a cli for run and migrate commands), and it is refresh the database.

What is the best practice to manage it. For example I have 1000 microservice, noone will type the service migrate when someone refresh the models. I thinking about a centralized database service, where we just add a new column and it will store all the models with all migration. The only problem, how will the services get to know about database model changes. This is how we store for example a user in a service:

type User struct {
    ID        uint           `gorm:"column:id;not null" sql:"AUTO_INCREMENT"`
    Name      string         `gorm:"column:name;not null" sql:"type:varchar(100)"`
    Username  sql.NullString `gorm:"column:username;not null" sql:"type:varchar(255)"`
}

func (u *User) TableName() string {
    return "users"
}
3
I am a bit confused what your definition of 'microservice' is. When you say 'microservice' do you mean a single instance of an application?HenryTK
Where are you typing service migrate? How is this done?HenryTK
@HenryTK I extend it.PumpkinSeed

3 Answers

4
votes

Depending on your use cases, MySQL Cluster might be an option. Two phase commits used by MySQL Cluster make frequent writes impractical, but if write performance isn't a big issue then I would expect MySQL Cluster would work out better than connection pooling or queuing hacks. Certainly worth considering.

3
votes

If I'm understanding your question correctly, you're trying to still use one MySQL instance but with many microservices.

There are a couple of ways to make an SQL system work:

  1. You could create a microservice-type that handles data inserts/reads from the database and take advantage of connection pooling. And have the rest of your services do all their data read/writes through these services. This will definitely add a bit of extra latency to all your writes/reads and likely be problematic at scale.

  2. You could attempt to look for a multi-master SQL solution (e.g. CitusDB) that scales easily and you can use a central schema for your database and just make sure to handle edge cases for data insertion (de-deuping etc.)

  3. You can use data-streaming architectures like Kafka or AWS Kinesis to transfer your data to your microservices and make sure they only deal with data through these streams. This way, you can de-couple your database from your data.

The best way to approach it in my opinion is #3. This way, you won't have to think about your storage at the computation layer of your microservice architecture.

Not sure what service you're using for your microservices, but StdLib forces a few conversions (e.g. around only transferring data through HTTP) that helps folks wrap their head around it all. AWS Lambda also works very well with Kinesis as a source to launch the function which could help with the #3 approach.

Disclaimer: I'm the founder of StdLib.

2
votes

If I understand your question correctly it seems to me that there may be multiple ways to achieve this.

One solution is to have a schema version somewhere in the database that your microservices periodically check. When your database schema changes you can increase the schema version. As a result of this if a service notices that the database schema version is higher than the current schema version of the service it can migrate the schema in the code which gorm allows.

Other options could depend on how you run your microservices. For example if you run them using some orchestration platform (e.g. Kubernetes) you could put the migration code somewhere to run when your service initializes. Then once you update the schema you can force a rolling refresh of your containers which would in turn trigger the migration.