diff --git a/README.md b/README.md index 8a2e117..8ae7fd1 100644 --- a/README.md +++ b/README.md @@ -206,19 +206,20 @@ Hi, 欢迎来到 ElemeFE, 如标题所示本教程的目的是教你如何通过 [阅读更多](sections/util.md) -## 存储 +## [存储](sections/storage.md) -* `[Point]` Sql -* `[Point]` NoSql -* `[Point]` 缓存 -* `[Point]` 数据一致性 +* [`[Point]` Mysql](sections/storage.md#mysql) +* [`[Point]` Mongodb](sections/storage.md#mongodb) +* [`[Point]` 数据一致性](sections/storage.md#数据一致性) +* [`[Point]` 缓存](sections/storage.md#缓存) ### 常见问题 -* 索引有什么用,大致原理是什么?设计索引有什么注意点? -* Session/Cookie 有什么区别? -* 连接超时有可能是什么问题导致的? -* 什么情况下数据会出现脏读? 如何避免? +* 备份数据库与 M/S, M/M 等部署方式的区别? [[more]](sections/storage.md#q-deploy) +* 索引有什么用,大致原理是什么? 设计索引有什么注意点? [[more]](sections/storage.md#索引) +* Monogdb 连接问题(超时/断开等)有可能是什么问题导致的? [[more]](sections/storage.md#Mongodb) +* 什么情况下数据会出现脏数据? 如何避免? [[more]](sections/storage.md#数据一致性) +* redis 与 memcached 的区别? [[more]](sections/storage.md#缓存) `更多整理中` diff --git a/assets/storage.jpeg b/assets/storage.jpeg new file mode 100755 index 0000000..19d7c04 Binary files /dev/null and b/assets/storage.jpeg differ diff --git a/sections/error.md b/sections/error.md index d6a077d..96f23a9 100644 --- a/sections/error.md +++ b/sections/error.md @@ -134,7 +134,7 @@ Error: test error 错误栈中仅输出到 test 函数内调用的地方位置, 再往上 main 的调用信息就丢失了. 也就是说如果你的函数调用深度比较深的情况下, 你使用异步调用某个函数出错了的情况下追溯这个异步的调用是一个很困难的事情, 因为其之上的栈都已经丢失了. 如果你用过 [async](https://github.com/caolan/async) 之类的模块, 你还可能发现, 报错的 stack 会非常的长而且曲折, 光看 stack 很难去定位问题. -这项目不大/作者清楚的情况下不是问题, 但是当项目大起来, 开发人员多起来之后, 这样追溯错误会变得异常痛苦. 关于这个问题, 在上文中提到 [错误处理的最佳实践](https://cnodejs.org/topic/55714dfac4e7fbea6e9a2e5d) 中, 关于 `编写新函数的具体建议` 那一带的内容有描述到. 通过使用 [verror](https://www.npmjs.com/package/verror) 这样的方式, 让 Error 一层层封装, 并在每一层将错误的信息一层层的包上, 最后拿到的 Error 直接可以从 message 中获取用于定位问题的关键信息. +这在项目不大/作者清楚的情况下不是问题, 但是当项目大起来, 开发人员多起来之后, 这样追溯错误会变得异常痛苦. 关于这个问题, 在上文中提到 [错误处理的最佳实践](https://cnodejs.org/topic/55714dfac4e7fbea6e9a2e5d) 中, 关于 `编写新函数的具体建议` 那一带的内容有描述到. 通过使用 [verror](https://www.npmjs.com/package/verror) 这样的方式, 让 Error 一层层封装, 并在每一层将错误的信息一层层的包上, 最后拿到的 Error 直接可以从 message 中获取用于定位问题的关键信息. 以昨天的数据为准(2017-3-13)各位只要对比一下看看 npm 上上个月 [verror](https://www.npmjs.com/package/verror) 的下载量 `1100w` 比 [express](https://www.npmjs.com/package/express) 的 `1070w` 还高. 应该就能感受到这种写法有多流行了. diff --git a/sections/module.md b/sections/module.md index 4701081..d7d69b8 100644 --- a/sections/module.md +++ b/sections/module.md @@ -1,8 +1,9 @@ # 模块 -* [`[Basic]` 模块机制](https://github.com/ElemeFE/node-interview/blob/master/sections/module.md#模块机制) -* [`[Basic]` 热更新](https://github.com/ElemeFE/node-interview/blob/master/sections/module.md#热更新) -* [`[Basic]` 上下文](https://github.com/ElemeFE/node-interview/blob/master/sections/module.md#上下文) +* [`[Basic]` 模块机制](#模块机制) +* [`[Basic]` 热更新](#热更新) +* [`[Basic]` 上下文](#上下文) +* [`[Basic]` 包管理](#包管理) ## 常见问题 @@ -17,7 +18,8 @@ 其他还有很多内容也是属于很 '基础' 的 Node.js 问题 (例如异步/线程等等), 但是由于归类的问题并没有放在这个分类中. 所以这里只简单讲几个之后没归类的基础问题. -### 模块机制 + +## 模块机制 node 的基础中毫无疑问的应该是有关于模块机制的方面的, 也即 `require` 这个内置功能的一些原理的问题. @@ -68,7 +70,7 @@ function require(...) { 再晋级一点, 众所周知, node 的模块机制是基于 [`CommonJS`](http://javascript.ruanyifeng.com/nodejs/module.html) 规范的. 对于从前端转 node 的同学, 如果面试官想问的难一点会考验关于 [`CommonJS`](http://javascript.ruanyifeng.com/nodejs/module.html) 的一些问题. 比如比较 `AMD`, `CMD`, [`CommonJS`](http://javascript.ruanyifeng.com/nodejs/module.html) 三者的区别, 包括询问关于 node 中 `require` 的实现原理等. -### 热更新 +## 热更新 从面试官的角度看, `热更新` 是很多程序常见的问题. 对客户端而言, 热更新意味着不用换包, 当然也包含着 md5 校验/差异更新等复杂问题; 对服务端而言, 热更新意味着服务不用重启, 这样可用性较高同时也优雅和有逼格. 问的过程中可以一定程度的暴露应聘程序员的水平. @@ -80,7 +82,7 @@ function require(...) { 所以这个问题其实本身其实是值得商榷的, 可能是典型的 [`X-Y Problem`](http://coolshell.cn/articles/10804.html), 不过聊起来确实是可以暴露水平. -### 上下文 +## 上下文 如果你已经了解 ①② 那么你也应该了解, 对于 Node.js 而言, 正常情况下只有一个上下文, 甚至于内置的很多方面例如 `require` 的实现只是在启动的时候运行了[内置的函数](https://github.com/nodejs/node/tree/master/lib). @@ -111,3 +113,22 @@ vm.runInThisContext(code)(require); 这种执行方式与 eval 和 Function 有明显的区别. 关于 VM 更多的一些接口可以先阅读[官方文档 VM (虚拟机)](https://nodejs.org/dist/latest-v6.x/docs/api/vm.html) 讲完这个知识点, 这里留下一个简单的问题, 既然可以通过新的上下文来避免污染, 那么`为什么 Node.js 不给每一个 `.js` 文件以独立的上下文来避免作用域被污染?` (反应不过来的同学还是别投简历了, 微笑脸) + + +## 包管理 + + +整理中... + +为什么我装了全局, 但是提示我 not found + +npm +yarn + +锁版本 + +lerna:一个用户管理多个包模块的工具。 + +left-pad事件 + +greenkeeper 等 diff --git a/sections/storage.md b/sections/storage.md new file mode 100644 index 0000000..67dacf0 --- /dev/null +++ b/sections/storage.md @@ -0,0 +1,139 @@ +# 存储 + +* `[Point]` Sql +* `[Point]` NoSql +* `[Point]` 缓存 +* `[Point]` 数据一致性 + +## 简介 + +科班的同学可以了解一下[数据库范式](http://www.cnblogs.com/CareySon/archive/2010/02/16/1668803.html), 在 ElemeFe 面试不会问, 但是其他地方可能会问 (比如阿里). + +> 备份数据库与 M/S, M/M 等部署方式的区别? + +关于数据库基于各种模式的特点全部可以通过以下图片分清: + +![storage](/assets/storage.jpeg) + +图片出处:Google App Engine 的 co-founder Ryan Barrett 在 2009 年的 google i/o 上的演讲 [《Transaction Across DataCenter》](http://snarfed.org/transactions_across_datacenters_io.html)(视频: http://www.youtube.com/watch?v=srOgpXECblk) + + +## Mysql + +### 存储引擎 + +|attr|MyISAM|InnoDB| +|----|----|----| +|Locking|Table-level|Row-level| +|designed for|need of speed|high volume of data| +|foreign keys | × (DBMS) | ✓ (RDBMS)| +|transaction | × | ✓ | +|fulltext search | ✓ | × | +|scene| lots of select | lots of insert/update | +|count rows| fast | slow | +|auto_increment | fast | slow | + +* 你的数据库有外键吗? +* 你需要事务支持吗? +* 你需要全文索引吗? +* 你经常使用什么样的查询模式? +* 你的数据有多大? + +参见 [MYSQL: INNODB 还是 MYISAM?](http://coolshell.cn/articles/652.html) + +### 索引 + +索引是用空间换时间的一种优化策略. 推荐阅读: [mysql索引类型](http://www.cnblogs.com/cq-home/p/3482101.html) + +## Mongodb + +> Monogdb 连接问题(超时/断开等)有可能是什么问题导致的? + +* 网络问题 +* 任务跑不完, 超过了 driver 的默认链接超时时间 (如 30s) +* Monogdb 宕机了 +* 超过了连接空闲时间 (connection idle time) 被断开 +* fd 不够用 (ulimit 设置) +* mongodb 最大连接数不够用 (可能是连接未复用导致) +* etc... + + +replset + +aggregate + +整理中 + +## 数据一致性 + +关于数据一致性推荐看陈皓的[分布式系统的事务处理](http://www.infoq.com/cn/articles/distributed-system-transaction-processing) + +> 什么情况下数据会出现脏数据? 如何避免? + +* 从 A 帐号中把余额读出来 +* 对 A 帐号做减法操作 +* 把结果写回 A 帐号中 +* 从 B 帐号中把余额读出来 +* 对 B 帐号做加法操作 +* 把结果写回 B 帐号中 + +为了数据的一致性, 这6件事, 要么都成功做完, 要么都不成功, 而且这个操作的过程中, 对A、B帐号的其它访问必需锁死, 所谓锁死就是要排除其它的读写操作, 否则就会出现脏数据 ---- 即数据一致性的问题. + +这个问题并不仅仅出现在数据库操作中, 普通的并发以及并行操作都可能导致出现脏数据. 避免出现脏数据通常是从架构上避免或者采用事务的思想处理. + +### 矛盾 + +* 1)要想让数据有高可用性,就得写多份数据 +* 2)写多份的问题会导致数据一致性的问题 +* 3)数据一致性的问题又会引发性能问题 + +强一致性必然导致性能短板, 而弱一致性则有很好的性能但是存在数据安全(灾备数据丢失)/一致性(脏读/脏写等)的问题. + +目前 Node.js 业内流行的主要是与 Mongodb 配合, 在数据一致性方面属于短板. + +### 事务 + +事务并不仅仅是 sql 数据库中的一个功能, 也是分布式系统开发中的一个思想, 事务在分布式的问题中可以称为 "两阶段提交" (一下引用陈皓原文) + +第一阶段: + +* 协调者会问所有的参与者结点,是否可以执行提交操作。 +* 各个参与者开始事务执行的准备工作:如:为资源上锁,预留资源,写undo/redo log…… +* 参与者响应协调者,如果事务的准备工作成功,则回应“可以提交”,否则回应“拒绝提交”。 + +第二阶段: + +* 如果所有的参与者都回应“可以提交”,那么,协调者向所有的参与者发送“正式提交”的命令。参与者完成正式提交,并释放所有资源,然后回应“完成”,协调者收集各结点的“完成”回应后结束这个Global Transaction。 +* 如果有一个参与者回应“拒绝提交”,那么,协调者向所有的参与者发送“回滚操作”,并释放所有资源,然后回应“回滚完成”,协调者收集各结点的“回滚”回应后,取消这个Global Transaction。 + +异常: + +* 如果第一阶段中,参与者没有收到询问请求,或是参与者的回应没有到达协调者。那么,需要协调者做超时处理,一旦超时,可以当作失败,也可以重试。 +* 如果第二阶段中,正式提交发出后,如果有的参与者没有收到,或是参与者提交/回滚后的确认信息没有返回,一旦参与者的回应超时,要么重试,要么把那个参与者标记为问题结点剔除整个集群,这样可以保证服务结点都是数据一致性的。 +* 第二阶段中,如果参与者收不到协调者的commit/fallback指令,参与者将处于“状态未知”阶段,参与者完全不知道要怎么办。 + + +## 缓存 + +> redis 与 memcached 的区别? + +|attr|memcached|redis| +|----|----|----| +|struct|key/value|key/value + list, set, hash etc. | +|backup | × | ✓ | +|Persistence | × | ✓ | +|transcations | × | ✓ | +|consistency | strong (by cas) | weak | +|thread | multi | signle | +|memory | physical | physical & swap | + + +## 其他 + +zookeeper +kafka +storm +hadoop +spark + +