本帖最后由 逆风TO 于 2018-4-25 16:46 编辑
公司名称:西安亚创科技
公司地址:西安雁塔区沣惠南路
公司规模:20-99人
主要业务:医疗项目公司照片:
1. 项目介绍可以根据以下要点来说明一下。 面试可能会做一些试探性的问题。比如问你的项目中有多少张表。这一个问题会在整个面试中问很多次,主要目的是试探一次你回答的是否一致,如果不一致,就说明没有做过这样的项目。 a) 明确项目的周期。 b) 明确项目的价值。(为什么做这个项目,它解决了用户什么痛点,它带来什么价值?) c) 明确项目的功能。(这个项目涉及哪些功能?) d) 明确项目的技术。(这个项目用到哪些技术?) e) 明确个人在项目中的位置和作用。(你在这个项目的承担角色?) f) 明确项目的整体架构。 g) 明确项目的优缺点,如果重新设计你会如何设计。 h) 明确项目的亮点。(这个项目有什么亮点?) i) 明确技术成长。(你通过这个项目有哪些技术成长?) 2. 数据库反模式设计 这个问题主要考验的是否在项目创建过数据表,并且在创建数据表的也会考虑到业务关联度。数据表设计的不好,在开发中会遇到大量问题,增加开发难度。这个问题还是很有实际意义的。 数据库范式是为解决关系数据库中数据冗余、更新异常、插入异常、删除异常问题而引入的。简单的理解,数据库范式可以避免数据冗余,减少数据库的空间,并且减轻维护数据完整性的麻烦。 第一范式(1NF) 第一范式,强调属性的原子性约束,要求属性具有原子性,不可再分解。 举个例子,活动表(活动编码,活动名称,活动地址),假设这个场景中,活动地址可以细分为国家、省份、城市、市区、位置,那么就没有达到第一范式。 第二范式(2NF) 第二范式,强调记录的唯一性约束,表必须有一个主键,并且没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。 举个例子,版本表(版本编码,版本名称,产品编码,产品名称),其中主键是(版本编码,产品编码),这个场景中,数据库设计并不符合第二范式,因为产品名称只依赖于产品编码。存在部分依赖。所以,为了使其满足第二范式,可以改造成两个表:版本表(版本编码,产品编码)和产品表(产品编码,产品名称)。 第三范式(3NF) 第三范式,强调属性冗余性的约束,即非主键列必须直接依赖于主键。 举个例子,订单表(订单编码,顾客编码,顾客名称),其中主键是(订单编码),这个场景中,顾客编码、顾客名称都完全依赖于主键,因此符合第二范式,但是顾客名称依赖于顾客编码,从而间接依赖于主键,所以不能满足第三范式。为了使其满足第三范式,可以拆分两个表:订单表(订单编码,顾客编码)和顾客表(顾客编码,顾客名称),拆分后的数据库设计,就可以完全满足第三范式的要求了。 值得注意的是,第二范式的侧重点是非主键列是否完全依赖于主键,还是依赖于主键的一部分。第三范式的侧重点是非主键列是直接依赖于主键,还是直接依赖于非主键列。 反模式 范式可以避免数据冗余,减少数据库的空间,减轻维护数据完整性的麻烦。 然而,通过数据库范式化设计,将导致数据库业务涉及的表变多,并且可能需要将涉及的业务表进行多表连接查询,这样将导致性能变差,且不利于分库分表。因此,出于性能优先的考量,可能在数据库的结构中需要使用反模式的设计,即空间换取时间,采取数据冗余的方式避免表之间的关联查询。至于数据一致性问题,因为难以满足数据强一致性,一般情况下,使存储数据尽可能达到用户一致,保证系统经过一段较短的时间的自我恢复和修正,数据最终达到一致。 需要谨慎使用反模式设计数据库。一般情况下,尽可能使用范式化的数据库设计,因为范式化的数据库设计能让产品更加灵活,并且能在数据库层保持数据完整性。 有的时候,提升性能最好的方法是在同一表中保存冗余数据,如果能容许少量的脏数据,创建一张完全独立的汇总表或缓存表是非常好的方法。举个例子,设计一张“下载次数表”来缓存下载次数信息,可使在海量数据的情况下,提高查询总数信息的速度。 另外一个比较典型的场景,出于扩展性考虑,可能会使用 BLOB 和 TEXT 类型的列存储JSON 结构的数据,这样的好处在于可以在任何时候,将新的属性添加到这个字段中,而不需要更改表结构。但是,这个设计的缺点也比较明显,就是需要获取整个字段内容进行解码来获取指定的属性,并且无法进行索引、排序、聚合等操作。因此,如果需要考虑更加复杂的使用场景,更加建议使用 MongoDB 这样的文档型数据库。 3. Redis的持久化Redis的应用已经是越来越广了,使用起来的技术难度也不高。持久化本身和运维相关了。但是很多公司没有专门的运维,他们需要的程序猿面面具道,不止是会简单的CRUD就行了。 还要能够解决一些突发性的问题。 甚至在架构设计上线的时候给一定的方案。
Redis是一个支持持久化的内存数据库,通过持久化机制把内存中的数据同步到硬盘文件来保证数据持久化。当Redis重启后通过把硬盘文件重新加载到内存,就能达到恢复数据的目的。 RDB RDB是Redis默认的持久化方式。按照一定的时间周期策略把内存的数据以快照的形式保存到硬盘的二进制文件。即Snapshot快照存储,对应产生的数据文件为dump.rdb,通过配置文件中的save参数来定义快照的周期。 # 快照的文件名 dbfilename dump.rdb # 存放快照的目录 dir /var/lib/redis # 在进行镜像备份时,是否进行压缩。 # yes:压缩,但是需要一些cpu的消耗。 # no:不压缩,需要更多的磁盘空间。 rdbcompression yes #900秒后且至少1个key发生变化时创建快照 save 900 1 #300秒后且至少10个key发生变化时创建快照 save 300 10 #60秒后且至少10000个key发生变化时创建快照 save 60 10000 一旦数据库出现问题,那么我们的RDB文件中保存的数据并不是全新的,从上次RDB文件生成到Redis停机这段时间的数据全部丢掉了。例如,每隔5分钟或者更长的时间来创建一次快照,Redis停止工作时(例如意外断电)就可能丢失最近几分钟的数据。 AOF Redis会将每一个收到的写命令都通过Write函数追加到文件最后,类似于MySQL的binlog。当Redis重启是会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。 # 是否开启AOF,默认关闭(no) appendonly yes 由于Linux会把对文件的写入操作通过buffer缓冲,因此Linux可能不是立即写入到文件,有对视数据的风险。Redis有三种不同的fsync策略供选择:no fsync at all、 fsync every second、 fsync at every query。默认为fsync every second此时的写性能仍然很好,且最坏的情况下可能丢失一秒钟的写操作。 # Redis支持三种不同的刷写模式: #每次收到写命令就立即强制写入磁盘,是最有保证的完全的持久化,但速度也是最慢的,一般不推荐使用。 # appendfsync always #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,是受推荐的方式。 appendfsync everysec #完全依赖OS的写入,一般为30秒左右一次,性能最好但是持久化最没有保证,不被推荐。 # appendfsync no AOF带来了另一个问题,持久化文件会变得越来越大。比如,我们调用INCR test命令100次,文件中就必须保存全部的100条命令,但其实99条都是多余的。因为要恢复数据库的状态其实文件中保存一条SET test 100就够了。为了合并重写AOF的持久化文件,Redis提供了bgrewriteaof命令。收到此命令后,Redis将使用与快照类似的方式将内存中的数据以命令的方式保存到临时文件中,最后替换原来的文件,以此来实现控制AOF文件的合并重写。由于是模拟快照的过程,因此在重写AOF文件时并没有读取旧的AOF文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的AOF文件。 # AOF文件名 appendfilename appendonly.aof #当进程中BGSAVE或BGREWRITEAOF命令正在执行时不阻止主进程中的fsync()调用(默认为no,当存在延迟问题时需调整为yes) no-appendfsync-on-rewrite no #当AOF增长率为100%且达到了64mb时开始自动重写AOF auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
4. 前后端分离
前后端分离已经不止是在大的互联网项目中用到了。我面试中的一家公司做的是ERP就是使用的前后端分离。 前后端分离是什么 我们来回顾下传统的 MVC 模式,客户端发送 AJAX 请求,服务端接受到该请求并返回 JSON 数据返回给客户端,客户端解析 JSON 进行页面渲染。
现在,为了提高开发效率,细化职责,前后端分离的需求越来越被重视,服务端负责业务/数据接口,前端负责展现/交互逻辑。如果将浏览器这一端视为前端,而服务器这一端视为服务端的话,可以将以上的MVC 模式,进行改造成前后端分离模式。
为什么需要前后端分离 有了前后端分离模式,前端人员更加关注界面展现/交互逻辑,服务端人员更加关注业务/数据接口,分工明确,职责清晰。 前端职责:页面UI,页面展示、交互、渲染,用户体验等。 后端职责:数据存储,业务逻辑,RESTful 接口,性能、可用性、伸缩性、扩展性、安全性等。 此外,当我们的存在多端场景,例如,一个服务端RESTful API,按照这种方式 Web/iOS/Android/PC/U3D 五个前端对于后端来说就无差别了,这是多么棒的设计啊。 前后端分离,最佳实践 简单分离模式 我们采用的方案是 REST 服务这个轻量级的 Web 服务,客户端发送 AJAX 调用服务端 RESTFul API 接口请求,服务端收到请求后将 JSON 格式的响应结果发送给客户端,这样就完成了一次交互。
服务端渲染模式 这种模式,基本可以满足我们一般产品的需求。然而,对于需要做SEO的产品,这种方式就有点力不从心了。因为,重要内容都在前端进行异步组装,这样是无法被搜索引擎收录的,所以必须要考虑服务端渲染才可以被SEO。 服务端渲染模式,结合我之前的项目场景,列举两种方式。 方式一,JSP渲染 通过JSP进行渲染。这个方式,实际上,就是在前端项目中加入Java代码,通过JSP作为模板渲染。
方式二,静态页渲染 通过FreeMarker生成静态页进行渲染。这个方式,需要考虑动静分离,CDN分发等场景。
Node.js渲染模式 对于上面的方案,存在一个重要的问题,前端人员需要涉及Java技术,无法达到前后端解耦。随着Node.js技术的普及,我们把渲染的工作从服务端抽出来到前端,明确的前后端职责划分。
总结 从传统的 MVC 模式,演变到前后端分离模式,可以让各端变得更专注。今天的话题,结合我之前的项目场景,主要简单介绍了简单分离模式,JSP渲染模式,静态页渲染模式,Node.js渲染模式。
|