网易社招面试问题及答案
1.redis有哪几种数据结构?给你一个key怎么知道是用的哪种结构?
字符串
使用string时,redis大多数情况下并不会理解或者解析其含义,无论使用json、xml还是纯文本在redis看来都是一样的,只是一个字符串,只能进行strlen、append等对字符串通用的操作,无法针对其内容进一步操作。其基本操作命令有set、get、strlen、getrange、append
SET key value
GET key
STRLEN key
GETRANGE key start end
APPEND key value
在大多数情况之外,就是string中存储的为纯数字的情况,redis可以将字符串当做数字进行进一步操作,这些操作包括decr、decrby、incr、incrby和incrbyfloat。
hash
使用hash时,在我看来,就是value本身就是一组key-value对,不过redis将这里的key称为field(但是hkeys命令为什么不叫hfields命令呢哈哈),也就是value是一组field-value对。其基本操作命令有hset、hget、hmset、hmget、hgetall、hkeys和hdel:
HSET key field value
HGET key field
HMSET key field value [field value ...]
HMGET key field [field ...]
HGETALL key
HKEYS key
HDEL key field [field ...]
list
使用list时,value就是一个string数组,操作这组string时,可以像对待栈一样使用pop和push操作,但是这个栈两端都能进行操作;也可以像对待数组一样使用一个index参数来操作。list的操作命令略杂,主要分为两类:L开头的和R开头的,L代表LEFT或者LIST,进行一些从列表左端进行的操作,或者一些与端无关的操作;R代表RIGHT,进行一些从列表右端进行的操作。
set
set用于存储一组不重复的值,也可以进行一些集合的操作,就像数学上的集合,它是无序的。基本操作有sadd和sismember:
SADD key member [member ...]
SISMEMBER key member
集合操作有:求交sinter、求并sunion和求差sdiff:
SINTER key [key ...]
SUNION key [key ...]
SDIFF key [key ...]
sorted set
sorted set类似set,但是sorted set里每个元素都有一个score,这个score可用于排序和排名。基本操作有zadd、zcount、zrank:
ZADD key score member [score member ...]
ZCOUNT key min max
ZRANK key member
2.怎么查看所有的key?redis怎么切换库?怎么清数据?
redis查看所有key
keys *
redis切换库
select index, 执行成功后注意端口之后多了索引[index]
redis清数据
flushall
3.描述下redis淘汰策略?如果没有数据可以淘汰或者没有配置淘汰策略读请求可以正常执行吗?
volatile-lru
从设置过期时间的数据集(server.db[i].expires)中挑选出最近最少使用的数据淘汰。没有设置过期时间的key不会被淘汰,这样就可以在增加内存空间的同时保证需要持久化的数据不会丢失。
volatile-ttl
除了淘汰机制采用LRU,策略基本上与volatile-lru相似,从设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰,ttl值越大越优先被淘汰。
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。当内存达到限制无法写入非过期时间的数据集时,可以通过该淘汰策略在主键空间中随机移除某个key。
allkeys-lru
从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰,该策略要淘汰的key面向的是全体key集合,而非过期的key集合。
allkeys-random
从数据集(server.db[i].dict)中选择任意数据淘汰。
no-enviction
禁止驱逐数据,也就是当内存不足以容纳新入数据时,新写入操作就会报错,请求可以继续进行,线上任务也不能持续进行,采用no-enviction策略可以保证数据不被丢失,这也是系统默认的一种淘汰策略。
上述是Redis的6种淘汰策略,关于使用这6种策略,开发者还需要根据自身系统特征,正确选择或修改驱逐。
- 在Redis中,数据有一部分访问频率较高,其余部分访问频率较低,或者无法预测数据的使用频率时,设置allkeys-lru是比较合适的。
- 如果所有数据访问概率大致相等时,可以选择allkeys-random。
- 如果研发者需要通过设置不同的ttl来判断数据过期的先后顺序,此时可以选择volatile-ttl策略。
- 如果希望一些数据能长期被保存,而一些数据可以被淘汰掉时,选择volatile-lru或volatile-random都是比较不错的。
- 由于设置expire会消耗额外的内存,如果计划避免Redis内存在此项上的浪费,可以选用allkeys-lru 策略,这样就可以不再设置过期时间,高效利用内存了。
Redis缓存功能,是由edis.c文件中的freeMemoryIfNeeded函数实现的。如果maxmemory被设置,那么每次在执行命令钱,该函数都会被调用来判断内存是否够用、释放内存、返回错误。如果没有足够的内存程序主逻辑将会阻止设置了REDIS_COM_DENYOOM flag的命令执行,对其返回command not allowed when used memory > ‘maxmemory’的错误消息。
区分不同的淘汰策略选择不同的key,Redis淘汰策略主要分为LRU淘汰、TTL淘汰、随机淘汰三种机制。
LRU淘汰
LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
在服务器配置中保存了 lru 计数器 server.lrulock,会定时(redis 定时程序 serverCorn())更新,server.lrulock 的值是根据 server.unixtime 计算出来进行排序的,然后选择最近使用时间最久的数据进行删除。另外,从 struct redisObject 中可以发现,每一个 redis 对象都会设置相应的 lru。每一次访问数据,会更新对应redisObject.lru
在Redis中,LRU算法是一个近似算法,默认情况下,Redis会随机挑选5个键,并从中选择一个最久未使用的key进行淘汰。在配置文件中,按maxmemory-samples选项进行配置,选项配置越大,消耗时间就越长,但结构也就越精准。
TTL淘汰
Redis 数据集数据结构中保存了键值对过期时间的表,即 redisDb.expires。与 LRU 数据淘汰机制类似,TTL 数据淘汰机制中会先从过期时间的表中随机挑选几个键值对,取出其中 ttl 最大的键值对淘汰。同样,TTL淘汰策略并不是面向所有过期时间的表中最快过期的键值对,而只是随机挑选的几个键值对。
随机淘汰
在随机淘汰的场景下获取待删除的键值对,随机找hash桶再次hash指定位置的dictEntry即可。
Redis中的淘汰机制都是几近于算法实现的,主要从性能和可靠性上做平衡,所以并不是完全可靠,所以开发者们在充分了解Redis淘汰策略之后还应在平时多主动设置或更新key的expire时间,主动删除没有价值的数据,提升Redis整体性能和空间。
在内存占用达到了maxmemory后,再向Redis写入数据时,Redis会根据配置的数据淘汰策略尝试淘汰数据,释放空间如果没有数据可以淘汰,或者没有配置数据淘汰策略,那么Redis会对所有写请求返回错误,但读请求仍然可以正常执行
4.你们项目里redis是单节点的吗?如果多节点怎么同步?
5.项目里用redis存哪些数据?为什么用redis?和jetty本地缓存有什么区别?
6.你用过哪些开源框架?最熟悉的是哪个?(这里我说了spring,所以后边的问题都是围绕spring的)
7.描述下spring的ioc和aop。
8.HTTP 1.1版本增加了哪些内容?有哪几种请求方式?
9.描述下HTTP三次握手和四次挥手过程?为什么需要四次挥手?为什么TIME_WAIT状态需要经过两个最大报文段生存时间才能到close状态?
10.浏览器发起一个请求到收到响应中间经历了哪些过程?知道多少就说多少,越详细越好。你常用哪一种注入方式?BeanFactory和ApplicationContext有什么区别?你们项目里用的哪个?说一下spring bean的生命周期。 AOP实现原理是什么?两种动态代理实现原理?JDK动态代理为什么要实现接口? 11.spring task是怎么实现的?
12.spring事务你是怎么用的?加了@Transcational注解spring都做了哪些工作?怎么知道事务执行成功了?
13.nginx有哪些模块?你比较熟悉哪个?
14.proxy_cache你是怎么配置的?缓存是存在哪里?具体是怎么命中缓存的? 简历里有写nginx,结果问得几个问题我都没答好,面试官就没再多问了,囧~事务隔离级别?mysql默认级别是什么?事务传播属性?spring默认是什么?嵌套事务子事务什么时候commit?
15.spring和springMVC是什么关系?有没有用过JdbcTemplate?
16.springMVC中对整个请求的处理流程是怎样的?返回json的话是用哪个view?
17.怎么查看某个进程中的线程?
18.怎么批量替换一个文件夹下所有文件中的一个字符?(sed命令)
19.有没有用过jps jmap jstack jstat 命令,分别说下有哪些常用参数,知道多少就说多少。 我这里结合自己用jmap jstack定位到线上问题的经验说的,答完后感觉面试官挺满意的,所以说实践很重要啊~
20.定义Integer x=20 Integer y=200 在内存里是个什么过程?
21.volite关键字的原理?它能保证原子性吗?AtomicInteger底层怎么实现的?
22.hashMap与concurrentHashMap原理和区别? hashMap什么情况下会出现循环链表?concurrentHashMap写的时候用什么锁?RenteenLock底层是怎么保证线程安全的?
23.mysql索引是怎么实现的?b+树有哪些特点?真实的数据存在哪里?
24.哪些情况下建索引?解释下最左匹配原则? 现在一个表有三列a b c,组合索引(a,b,c)查询的时候where a like ? and b=? and c=?能用到这个组合索引吗?为什么?
25.explain执行计划看过没有?其中type字段都有哪些值?分别代表什么?
26.你有哪些sql调优经验?
27.反射能获取到父类的私有方法吗?怎么防止反射破坏单例模式?
28.描述下JVM内存模型。每个区的作用是什么?堆内存的工作原理,为什么需要两个幸存区?只有一个行不行?老生代是用什么垃圾回收算法?
29.threadLocal关键字有用过吗?如果没有重写initialValue方法就直接get会怎样?
30.描述下多线程原理。怎么开启一个线程?start和run方法有什么区别? 怎么创建一个线程池,传入的参数分别什么含义?线程池是怎么实现维持核心线程数的?怎么实现一个自定义的拒绝策略?
31.Socket编程 nio(这一块我不太熟就说没了解过,面试官就没细问了)
32.设计一个系统,每天有100亿条数据,需要在后台做实时展示和查找。 我当时回答的大体思路是nginx负载均衡,消息队列存储,多线程读取,批量插入,数据库分库分表。 面试官根据我的回答又衍生出了很多问题,如消息队列存满了怎么办?(也就是消费跟不上生产)批量插入时某一条失败了有什么影响?怎么解决?分库分表应该怎么分?怎么解决数据迁移的问题?
33.用代码实现cat 1.log |grep a |sort |uniq -c |sort -rn 的功能。
34.如果现在有一台服务器突然变得很慢,怎么去定位问题?