侧边栏壁纸
博主头像
翻斗

开始一件事最好是昨天,其次是现在

  • 累计撰写 44 篇文章
  • 累计创建 42 个标签
  • 累计收到 2 条评论

多语言架构思考

翻斗
2021-11-07 / 0 评论 / 0 点赞 / 3,214 阅读 / 2,241 字

国际化、多语言

一般公司在创立之初,根本就没有概念(或者没有时间)来做5年后、10年后的技术架构(除非是连续创业、有前瞻性很强的技术团队或者领导),这是很自然的,因为默认最重要的就是处理好眼前的事,如果一开始就花了太多时间做未来规划,结果自己都撑不了3年,这就真的是没有脑子的行为了。

公司一开始的头号目标,一定是活下去。

撑过头几年的夭折高峰期,业务慢慢发展起来,慢慢的,技术需要迭代、需要更新、需要重新设计。这个时候就需要有一定的前瞻性

比如开始拆分单体结构,做成模块化服务,做成微服务,慢慢的上云,拥抱云原生(Cloud Native)/服务网格(Service Mesh)等等。

再比如,公司业务走向国际化,需要重新设计,如何更好的为其他语种的客户服务,如何做到国际化,支持多语言

几种多语言设计方案

1、单字段多实例方案

这种方案就是一种设计干到底,一把梭。 每次新增一个语种,就做成一个新的子站。每次新增一个站点就需要新增一个数据库集群。字段永远是那个字段,只不过内容变为对应的语言。

此方案部署实施简单,但是需要更多的成本,适合不差钱的公司采用。

  • 优点:简单
  • 缺点:成本高

2、列扩展方案

此方案就是每次来一个语言,就新增列,这个思考来也没什么难度,想得到的,但就是每次新增列的时候,会对数据库有影响。当数据量很大的时候,如何保证不影响用户体验的增加字段是个难题,大多需要提前准备做停机升级。如果要保持向后兼容,需要提前预留一些字段

  • 优点:简单
  • 缺点:扩展语言对业务影响大(除非预留字段),不同的表都需要维护一套类似方案

3、行扩展方案


此方案就是提前做好根据语言的区分,增加一个语言的映射表,每次增加一种语言,新增该映射表即可。新增语言对业务影响小。

  • 优点:新增语言对业务影响小,扩充平滑
  • 缺点:不同的表都需要维护一套类似方案

4、语言表集中维护

此方案就是为了解决前面提到的一个问题:不同的表都需要维护一套类似方案。该方案将全部的语言内容放到一个地方集中统一管理,各个表中要取对应的语言内容,根据映射id去语言表中拿对应的语言即可。

不过因为全部业务的多语言内容都放在一个表里面,很快就会达到瓶颈,需要及早的考虑分库分表的问题。

  • 优点:对业务影响小,统一管理语言
  • 缺点:语言表是瓶颈,需要注意性能问题

不同的方案有不同的优缺点,技术实现并没有银弹。我们需要根据具体的场景选择不同的方案,或者根据某个方案进行改造。

案例:跨境电商 2种语言 => 7种语言

跨境电商刚开始很多是先做一个只支持简体中文的,毕竟主要是为了远方的华人华侨留学生们服务,然后慢慢普及到汉语系的其他人。然后慢慢发展,需要挖掘英语系的客户,就支持英语。双语支持一大段时间之后,又想要支持更多的语言,比如说日语、韩语、西班牙语和越南语等。

前提:

  • 公司现在支持2种语言,采用的是上面的列扩展方式
  • 要影响更小的支持更多的5种语言
  • 业务量已经比较大

思考:要一口气新增5种语言,并且日后不知道要不要新增更多语言,最好是可扩展。基于现有方案,如果继续采用列扩展方式,会很麻烦,而且多个DB多个Table都需要一起扩充,基本上要停机更新。这个对于现有业务的冲击很大,直接放弃。

可以考虑采用语言表集中维护的办法,同时兼容现有结构,采用API Gateway做统一转换。

语言 翻译自 回写字段
zh-TW goods_name goods_name
ja goods_name_en goods_name_en
ko goods_name_en goods_name_en
es goods_name_en goods_name_en
vi goods_name_en goods_name_en

该方案有几个核心思路:

  • 1、异步翻译Job(下方蓝色三条线对应的),将业务表内容取出来异步翻译,然后存入翻译表。将翻译表的ID组成一个唯一标识(i18n#id#),回写到业务库(Goods表)
  • 2、用户访问,传入对应需要的语言,比如是韩语ko
  • 3、业务服务根据下面的映射提取表中数据
  • 4、拿到的数据{goods_name_en:"i18n#123#chocolate"}经过API Gateway的时候,调用I18N ServiceI18N Service根据已有内容前缀i18n#123#,提取其翻译对应ID(123),去翻译表中,找到对应语言(ko)的内容(초콜릿)
  • 5、返回翻译好的对应语言的内容 {goods_name_en:"초콜릿"}

这个方法有几个好处:

  • 1、充分利用现有字段,不再扩充
  • 2、业务代码变化极少,只需要在原有的基础上(简体中文 => goods_name, 英文 => goods_name_en) 变为(简体中文/繁体中文 => goods_name, 英文/日语/韩语/西班牙语/越南语 => goods_name_en)
  • 3、集中统一在API Gateway中做处理,没有更多代码/业务耦合
  • 4、上线简单,无需停机更新,滚动升级。可以按照业务情况,逐步上线不同项目,只需要异步进行提前翻译即可,未翻译的自动用原语言兜底。
  • 5、回滚方便。只需要将数据库中的i18n##xxx##头部去掉即可。

当然,这个只是一些基础的设计,后续还有更多需要处理,比如翻译表显然是瓶颈。不能放在单表里面,如果要做持久化,需要分库分表,添加多级缓存。因为只是做一个简单存取,没有更多业务逻辑,可以考虑使用ElasticsearchK-V数据库或者列式数据库(HBase等)存储以及使用等。

0

评论区