1、微服务开发为什么要网关?
微服务下一个系统按照模块或function被拆分为多个服务,但是像安全认证,流量控制,日志,监控等功能是每个服务都需要的,没有网关的话,我们就需要在每个服务中单独实现,这使得我们做了很多重复的事情并且没有一个全局的视图来统一管理这些功能。一般情况下,网关一般都会提供请求转发、安全认证(身份/权限认证)、流量控制、负载均衡、容灾、日志、监控这些功能。
至于微服务是否需要内部网关视具体架构情况而定,如果负载均衡用的是openresty,安全认证,流量控制,日志,监控等功能通过openresty处理时,则常见的内部网关gateway或zuul等可以省掉。
2、限流的算法有哪些?
1、固定窗口计数器算法:
规定我们单位时间处理的请求数量。比如我们规定我们的一个接口一分钟只能访问10次的话。使用固定窗口计数器算法的话可以这样实现:给定一个变量counter来记录处理的请求数量,当1分钟之内处理一个请求之后counter+1,1分钟之内的如果counter=100的话,后续的请求就会被全部拒绝。等到 1分钟结束后,将counter回归成0,重新开始计数(p.s.:只要过了一个周期就讲counter回归成0)。这种限流算法无法保证限流速率,因而无法保证突然激增的流量。比如我们限制一个接口一分钟只能访问10次的话,前半分钟一个请求没有接收,后半分钟接收了10个请求。
有弊端,一是没有办法限制速率,二是虽然单个窗口没有超出限制,但是如果一次请求集中在时间区间后半段,下一刚好集中在时间区间的前半段,这个两个一拼,从另一个角度看是允许限制的两倍。
2、滑动窗口计数器算法:
算的上是固定窗口计数器算法的升级版。滑动窗口计数器算法相比于固定窗口计数器算法的优化在于:它把时间以一定比例分片。例如我们的借口限流每分钟处理60个请求,我们可以把 1 分钟分为60个窗口。每隔1秒移动一次,每个窗口一秒只能处理 不大于 60(请求数)/60(窗口数) 的请求, 如果当前窗口的请求计数总和超过了限制的数量的话就不再处理其他请求。很显然:当滑动窗口的格子划分的越多,滑动窗口的滚动就越平滑,限流的统计就会越精确。
这种算法避免了固定窗口计数器带来的双倍突发请求,但时间区间的精度越高,算法所需的空间容量就越大。
3、漏桶算法:
我们可以把发请求的动作比作成注水到桶中,我们处理请求的过程可以比喻为漏桶漏水。我们往桶中以任意速率流入水,以一定速率流出水。当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率。如果想要实现这个算法的话也很简单,准备一个队列用来保存请求,然后我们定期从队列中拿请求来执行就好了。
4、令牌桶算法:
令牌桶算法也比较简单。和漏桶算法算法一样,我们的主角还是桶(这限流算法和桶过不去啊)。不过现在桶里装的是令牌了,请求在被处理之前需要拿到一个令牌,请求处理完毕之后将这个令牌丢弃(删除)。我们根据限流大小,按照一定的速率往桶里添加令牌。令牌桶算法可以说是对漏桶算法的改进。漏桶算法能限制请求的速率。而令牌桶算法在限制请求速率的同时还允许一定程度的突发调用。
3、谈一下数据库的读写分离?
读写分离主要是为了将对数据库的读写操作分散到不同的数据库节点上。 其实就是将数据库分为了主从库,一个主库用于写数据,多个从库完成读数据的操作,主从库之间通过某种机制进行数据的同步,是一种常见的数据库架构。
这样的话,就能够小幅提升写性能,大幅提升读性能。一般情况下,我们都会选择一主多从,也就是一台主数据库负责写,其他的从数据库负责读。主库和从库之间会进行数据同步,以保证从库中数据的准确性。这样的架构实现起来比较简单,并且也符合系统的写少读多的特点。
4、数据库读写分离会带来什么问题?如何解决?
问题1: 主库和从库的数据存在延迟,比如你写完主库之后,主库的数据同步到从库是需要时间的,这个时间差就导致了主库和从库的数据不一致性问题。这也就是我们经常说的主从同步延迟 。
解决这个问题:
可以在请求从库拿不到数据后,将读请求路由到主库处理,这种方案虽然会增加主库的压力,但是实现起来比较简单。
问题2:数据库连接池要进行区分。
解决这个问题:
可以通过应用层自己实现代码,不过增加了开发复杂度,也可以通过一些中间件来解决,例如mycat等。
问题3:为了保证高可用,读连接池要能够实现故障自动转移。
解决这个问题:
1.可以通过应用层自己实现代码,不过增加了开发复杂度,也可以通过一些中间件来解决,例如mycat等。
对于读写分离方案,在采用前,要先考虑是否可以通过加进程外缓存来解决,这样即可以起到分流的作用,代码层面复杂度也低,如果是kv的数据结构可以使用redis,如果是类sql数据结构可以使用ignite。
5、谈一下 SpringMVC 统一异常处理的思想和实现方式?
使用 SpringMVC 之后,代码的调用者是 SpringMVC 框架,也就是说最终的异常会抛到框架中,然后由框架指定异常处理类进行统一处理。
方式一: 创建一个自定义异常处理器(实现 HandlerExceptionResolver 接口),并实现里面的异常处理方法,然后将这个类交给 Spring 容器管理;
方式二: 在类上加注解(@ControllerAdvice)表明这是一个全局异常处理类在方法上加注解 (@ExceptionHandler), 在ExceptionHandler 中有一个value 属性,可以指定可以处理的异常类型。
6、数据库引擎InnoDB与MyISAM的区别?
InnoDB是 MySQL 默认的事务型存储引擎,只有在需要它不支持的特性时,才考虑使用其它存储引擎。实现了四个标准的隔离级别,默认级别是可重复读(REPEATABLE READ)。在可重复读隔离级别下,通过多版本并发控制(MVCC)+ 间隙锁(Next-Key Locking)防止幻影读。主索引是聚簇索引,在索引中保存了数据,从而避免直接读取磁盘,因此对查询性能有很大的提升。内部做了很多优化,包括从磁盘读取数据时采用的可预测性读、能够加快读操作并且自动创建的自适应哈希索引、能够加速插入操作的插入缓冲区等。支持真正的在线热备份。其它存储引擎不支持在线热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能也意味着停止读取。
MyISAM设计简单,数据以紧密格式存储。对于只读数据,或者表比较小、可以容忍修复操作,则依然可以使用它。提供了大量的特性,包括压缩表、空间数据索引等。不支持事务。不支持行级锁,只能对整张表加锁,读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操作的同时,也可以往表中插入新的记录,这被称为并发插入(CONCURRENT
INSERT)。可以手工或者自动执行检查和修复操作,但是和事务恢复以及崩溃恢复不同,可能导致一些数据丢失,而且修复操作是非常慢的。如果指定了DELAY_KEY_WRITE
选项,在每次修改执行完成时,不会立即将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。这种方式可以极大的提升写入性能,但是在数据库或者主机崩溃时会造成索引损坏,需要执行修复操作。
两者比较:
事务: InnoDB 是事务型的,可以使用 Commit 和 Rollback 语句。
并发: MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。
外键: InnoDB 支持外键。
备份: InnoDB 支持在线热备份。
崩溃恢复: MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。




