第二版 (5/14/2019更新)
React component example
<LanguageResource key = checkout.cfmMoney>Confirm Amount</LanguageResource>
数据库设计
Language Resource Table Schema
Key, OriginContent, LastUpdated, ContentLangId1, LastUpdatedLangId1, ContentLangId2, LastUpdatedLangId2, ...
Key一定是要有比较规范的name space, 避免出现同一个key被不同的developper使用修改。
Task Table Schema
Key, OriginContent, LastUpdated, LanguageId, TranslatorId, status, HtmlFileLink, prioritiy
一种做法: 网页修改完毕不等翻译完成就上线。
网页文件修改之后一种做法是直接deploy,用户load页面的时候会产生翻译请求。
这种做法的考虑基于是很多时候某个页面在某种语言很少会出现,没必要等全部翻译完再上线。
根据用户load的时候如果某个key找不到,就会自动产生一个translation request, 同时用英语做为fall back。 一个key被Request的次数越多他的优先级越高,
API:
GetTranlantion(key, originContent, url)
this API call may make internal call: RequestTranslatorService(key, originContent, url)
单词内容有变化? OriginalContent修改的情况
如果这个key的英文改了: 在translation的时候就会发现送过去的originalLanguageContent的数据库里的不一致!这种情况要做三件事情: 1。 更新数据库里的original content, 2。 更新originalContent 的last update time。 3. send update translation request.
如果翻译还没更新又来访问这个request了, 虽然内容一致,但翻译和原文的timestamp顺序相反,这时仍然使用旧的翻译,同时再发一次translation request.
updateTranslationAsOriginalContentUpdated(key, previousContent, newContent)
如果嫌慢(因为要写很多个任务)可以丢到一个message Queue里面去异步执行。
key , originalcontent, translantion.
如何翻译
getTranslation(key, OriginalLanguageContent, languageId)
如果找到,originalContent一致并且翻译的timestamp比数据库里originalContent的时间stamp要晚,则直接返回。如果找到但内容不一致/timestamp不对 则refer to original content修改的情况。
如果找不到就fall back为英语,同时增加一个翻译请求。这个翻译请求如果已经在task list里了,就更新优先级, 如果不在, 就新建。
如何给翻译员分配任务
根据翻译员的语言种类,从当前任务列表里先择优先级最高的一组翻译,最好是据有相同key前缀的(一般优先级也会相同, 因为一个页面里的key是同时更新优先级的)。同时更新Task table把当前任务设为pending,翻译员id也设置上. 这样别的翻译员就不会去拿同一个task。 可以再增加一个field记一下任务是什么时候开始的。如果一段时间任务并没有完成,则自动重新变成available.
getTranslationTask(languageId, amount, translatorId);
翻译员如何更新翻译
Api: enterTranslation(key, languageId, translated content, translatetimeStamp, originContentTimeStamp)
在更新数据库时候先check一下数据库里original content的time stamp, 如果翻译人员提交的original content的timestamp比较老, 则拒绝这次更新,返回outdated originalContent Exception.
如果更新成功, 则把更新的信息broadcast给所有存有cache的web服务器。也可以定期推送。
另外一种做法翻译完再上线。
另外一种做法是网页修改之后,直接extract新的key和修改过的key value pair. 这些key不翻译完新版网页就不上线。
Api: ExtractForTranslation(fileName) return a jobId
Using this jobId, the developper can see how much content has been already translated
全部翻译完成后翻译官把整个翻译的package发过来。发过来之后由系统统一deploy。但这样会delay上线速度。 此时翻译官也不会直接把翻译输入数据库。因为新网页还没上线, 翻译先上线会造成数据不一致。
Scale
可以把两张表都放到数据库里面。 Lanaguage Resource Table直接在每个webserver上做cache。如果数据库有更新,数据库服务器就会notify 其他所有的webserver更新cache。可以每十分钟做一次。
如何Sharding:
由于数据量不大,本身不一定需要sharding。可以按语言和对应的location sharding。
Indexing
LanguageResource直接按key查+就可以了, 本身就有index, 不需要再建index。
对于task Table要按 languageId + 状态 建 index,
task Table的primary index是 key + languageId,
每天半夜12点可以更新一下优先级,让所有的优先级衰减。删掉那些低于某些threhold的值。
-----------------------------我写的翻译系统第二版到这里结束-------------------------------------------------------------
参考文献:
相关的官方技术博客
https://medium.com/airbnb-engineering/launching-airbnb-jp-in-record-time-52f8b0af965d
技术文档 https://airbnb.io/polyglot.js/
其他 https://www.jiuzhang.com/qa/5054/ https://github.com/donnemartin/system-design-primer
4S 分析大法
Scenario:
前端人员使用一种语言(比如英语)设计前端。
menu label, 描述,免责条款,
前端人员release 英文版网页或内容 ==》 触发翻译系统extract 翻译事件 :翻译系统分析英文版文件,对比哪些句子/内容已经翻译过了,哪些句子/内容需要新翻译。==》 extract出新句子分发给翻译员。==》翻译员完成翻译任务之后返回给翻译系统。翻译系统输出多种语言包。
系统可以分为两种实现形式:
如果是网页更新比较慢而且是一组静态网页的话。
1。前端人员 2。 网页分析服务。 3数据库 4。 Combine 服务 5。翻译员。
这样的话,所有的内容在创建的时候都立马翻译好,可能有几个小时到一两天的delay。
这种的缺点是所有语言版本的发布会比较慢,因为所有内容都要翻译。
如果是像Airbnb这样的动态生成的网页(数据都是数据库里调出来的)
前端人员修改网页的时候,可以在修改完网页时自动发一个翻译的request 通知系统去翻译,但可能网页还没翻译完就上线了。
用户输入airbnb.cn网站地址,根据用户的地理语言信息,webserver在生成网页的时候发一个translate request. 把网页里对应的标签转换成相应的语言再返回给用户。相当于一个实时的翻译系统。不需要等待页面全部翻译完成再上线。如果一个词在本地cache里,先查本地cache, 如果不在本地cache,则可以跨过网络去查数据库的cache,如果数据库的cache里面也没有,则去数据库里找,找不到就用默认语言并且去待翻译数据库里面给该key增加一下优先级。 一个key被request的次数越多,它的优先级越高。
翻译人员从“待翻译数据库” 里拿出当前优先级最高的词, 翻译,输入系统。
API
GetTranslate(key, default, locale)
EnterTranslatedVersion(key, default, value, locale)
如果要改key 和default的话, 可以增加一个api, updateTranslate(key, new default, locale)
需要设计多牛的系统
怎么估算size??
还真不知道。 算一下有多少网页:每个网页有多少单词??还得再想想
Service
Translate Service
Translator task service
Client --> webServer
|
v
Front End -> Translate Service -> DataBase
^
|
v
Translator <--> Translate Task Service
Storage
Data model
Translation Table
用什么数据库? Redis (内存型), Cassandra, SQL + Memcached
Redis是纯粹的key -value pair: 如果用Redis
Key:Key + Locale, Value : content in language of locale + time stamp
如果用Cassandra, 三层结构。
Schema:
Row Key : Key ;
Column Key: Locale
Value: content in some language + time stamp
读取的时候要用Key + locale去读。
也可以用SQL,反正是读多写少,大不了用cache优化一下。
SQL也行。。。因为哪儿哪么多访问量
Task Table
这个量级很小,一个SQL就足够了。
Schema如下
Key,Original Language, To Language,优先级, status,
Working solution
前端人员把 key, English
优化:
按优先级排序,如果一个key被call的次数越多,优先级越高。 如果一个key四天都没有被call过,则自动清除出队列。
加速 优化perf
在Web Server端放一些Cache,有问题先查本地的cache,查不到再找DB。
建index, 只需要根据key 和locale建一个composite primary index就可以了。
bloom filter : 如果一个key不在bloom filter里面,则肯定不用找了。
关键问题: 如果DB更新了,如何第一时间更新那么多server:
DB主动发送push notification给Web Server.
需要设计TTL吗? 最好这样,不然如果某些push notification某种原因没有收到,就跪了。
Sharding
如果需要Sharding,则可以按语言按距离按国家Sharding。
非要按Hash code sharding的话,sharding key就是我们的key。其实并不需要sharding,一台机器是可以搞定的。
Consistent hashing 的概念
按String做为sharding key
Cache
Cache thru 和Cache aside都可以。但重要的是在服务器端直接cache, 就不用每次访问数据库了。
前端程序员不受后端设计的影响。
前端用key,和 value写在html里面。
translator有另一个portal输入翻译而且能马上看到效果
把对应的html存下来,直接调存下来的html显示。
再来就是有时候translator翻译错了修改之后怎么样才能更快的让大家看见(如果你有cache的话)
Broadcast,Server和DB 保持一个长链接,有新的变化立马通知。
网友评论