This page looks best with JavaScript enabled

How to Use a CDN to Further Separate Frontend and Backend

 ·  ☕ 6 min read

I have been optimizing a project recently. After mapping out the whole chain, I started improving it step by step and found many points that could be improved. What follows are some thoughts on the development model and the deployment approach. I hope they give you some inspiration.

1. Development Background

1.1 Deployment Approach

As shown above, here is a brief description of the application architecture.

It uses the classic three-tier architecture: access tier, logic tier, and storage tier. The access tier and the storage tier are services shared by all applications. The logic tier is deployed by K8S, and each application has multiple instances.

The access tier can handle a very large amount of concurrency; a single LVS distributes traffic to multiple Nginx instances.

The logic tier mainly packages the code in the form of a Slug into a base image, and then performs multi-instance deployment. To guarantee data consistency, the logic tier does not keep any state; all state must be managed through external services.

The storage tier provides various stateful services, such as MySQL and object storage.

1. 2 Development Model

As shown above, here is a brief explanation of the current development model.

We use a frontend-backend separated development model. The backend uses Django, and the frontend uses Webpack + Vuejs. The frontend and backend interact through index.html and APIs.

The developer service is divided into two parts: CI and CD.

CI, that is, developer continuous integration. Developers commit code to the same repository separately. To ensure development quality, a Merge Request process is followed. After the code is merged into the master branch, the CI Runner is triggered to run, compiles the frontend Webpack project, and then pushes the compiled frontend files and the backend code to the SVN release repository.

CD, the continuous deployment part, is mainly provided by PaaS Engine. This is a deployment engine provided by K8S.

2. Development Problems

Although a frontend-backend separated development model is adopted, in practice the same code repository is used. This is because PaaS Engine only supports SVN-based deployment. At the same time, PaaS Engine is a general-purpose deployment engine and does not adapt specifically to the frontend-backend development model.

Developing with the same code repository does not cause conflicts at the code level, since different directories are used, but it creates a hard coupling at the deployment level — the frontend and backend must be deployed together. This leads to a series of problems.

  • The code repository is large, and GitLab CI is slow at pushing to SVN
  • PaaS Engine is inefficient at forwarding frontend static files
  • During development iterations, online problems cannot be fixed promptly and effectively
  • The production environment cannot do canary testing; there is only one version
  • Repository permissions for frontend and backend are chaotic, and responsibilities are unclear
  • Access speed to the application varies greatly across regions and networks

3. More Separation Between Frontend and Backend

In my opinion, the greatest significance of frontend-backend separation lies in the separation of rights and responsibilities. Rights mean the freedom to choose technology, to explore something interesting and useful, to please yourself, and also to better develop the project. Responsibilities mean not only completing tasks on schedule, but also thinking about the sustainability of the project, optimizing its problems, and preventing possible risks.

The first step is to split the Git repository.

As shown above, we split the entire application into two Git repositories. Frontend engineers are responsible for the frontend Git repository, and backend engineers are responsible for the backend Git repository.

The second step is to deploy separately.

When PaaS Engine deploys, it pulls the code from the specified SVN repository. This is a constraint: application developers assumed that the code had to be packaged and integrated together before it could be deployed.

While optimizing the application, I gradually moved the frontend third-party plugins to the CDN. It suddenly occurred to me: why not put the entire set of frontend files on the CDN?

Of course we can! Using a CDN for static assets directly not only achieves high concurrency but also low latency, reducing differences in network and geography. It is absolutely the first choice for frontend deployment.

As shown above, the CD process is split into two independent, parallel steps. The backend still follows the previous release process: merge code in GitLab, push to SVN, and then release with the help of PaaS Engine. For the frontend, apart from the Merge Request and Code Review process on GitLab, deployment does not need to go through PaaS — it is published directly to the CDN.

Once these two steps are done, the rights and responsibilities of the frontend and backend are separated once again.

4. Version Management

When the frontend and backend shared one repository and were deployed together, versions were bound together, so there was no version mismatch problem. But once the frontend and backend are deployed separately, the problem of version management follows.

4.1 How the Frontend and Backend Manage Versioned Files

Frontend files are stored on the CDN, and version management can be achieved through an agreed-upon directory structure.

Assume the domain name is cdn.domain.com .

The storage relative paths are:

1
2
/:version_id/js/xxx.js
/:version_id/css/xxx.css

The corresponding full access paths are:

1
2
https://cdn.domain.com/:version_id/js/xxx.js
https://cdn.domain.com/:version_id/css/xxx.css

In the frontend-backend separated model, the backend still needs to serve the homepage. By controlling the version of the static files referenced in index.html, we can achieve version control over the frontend. Since there is only one backend release environment, and stateful services such as MySQL do not support rollback, once a database field changes, backend releases can only roll forward.

index.html

1
2
3
4
5
6
7
8
<script
  type="text/javascript"
  src="https://cdn.domain.com/{version_id}/js/vendors.js"
></script>
<script
  type="text/javascript"
  src="https://cdn.domain.com/{version_id}/js/app.js"
></script>

Here version_id is the frontend version number in the backend database. By modifying the version number according to a certain strategy, canary testing and A\B testing can be achieved.

4.2 Frontend-Backend Integration and Acceptance Strategy

After the frontend and backend code repositories are separated, each releases its own version.

However, a frontend version and a backend version do not necessarily form a releasable application version. For example, during a new iteration, the frontend has finished feature development [f5.3.1], but the current backend version [b3.4.4] is not ready.

For versions that are in the middle of iteration, we agreed on a release pattern and named it red-green release.

If the current frontend and backend versions pass integration and acceptance together, then the frontend and backend versions are marked green.

If either the frontend or the backend is adjusted in a way that affects the normal use of previous features, then the modified version is marked red.

Until the next integration version passes acceptance, the frontend and backend versions are marked green again.


WeChat Official Account
WRITTEN BY
WeChat Official Account