2024年最新7年Java老后端不能说的秘密:怎么样更好的优化Redis性能?,3面直接拿到offer

总结

面试前的“练手”还是很重要的,所以开始面试之前一定要准备好啊,不然也是耽搁面试官和自己的时间。

我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。

面试题及解析总结

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

大厂面试场景

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

知识点总结

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

(64位系统不限制内存,32位系统默认最多使用3GB内存)

数据量不可预估,并且内存也有限的话,尽量限制下redis使用的内存大小,这样可以避免redis使用swap分区或者出现OOM错误。(使用swap分区,性能较低,如果限制了内存,当到达指定内存之后就不能添加数据了,否则会报OOM错误。可以设置maxmemory-policy,内存不足时删除数据)

11、SLOWLOG [get/reset/len]

slowlog-log-slower-than 它决定要对执行时间大于多少微秒(microsecond,1秒 = 1,000,000 微秒)的命令进行记录。

slowlog-max-len 它决定 slowlog 最多能保存多少条日志,当发现redis性能下降的时候可以查看下是哪些命令导致的。

二、管道测试

redis的管道功能在命令行中没有,但是redis是支持管道的,在java的客户端(jedis)中是可以使用的:

image-20211031160004972

示例代码:

//注:具体耗时,和自身电脑有关(博主是在虚拟机中运行的数据)

/**

  • 不使用管道初始化1W条数据

  • 耗时:3079毫秒

  • @throws Exception

*/

@Test

public void NOTUsePipeline() throws Exception {

Jedis jedis = JedisUtil.getJedis();

long start_time = System.currentTimeMillis();

for (int i = 0; i < 10000; i++) {

jedis.set(“aa_”+i, i+“”);

}

System.out.println(System.currentTimeMillis()-start_time);

}

/**

  • 使用管道初始化1W条数据

  • 耗时:255毫秒

  • @throws Exception

*/

@Test

public void usePipeline() throws Exception {

Jedis jedis = JedisUtil.getJedis();

long start_time = System.currentTimeMillis();

Pipeline pipelined = jedis.pipelined();

for (int i = 0; i < 10000; i++) {

pipelined.set(“cc_”+i, i+“”);

}

pipelined.sync();//执行管道中的命令

System.out.println(System.currentTimeMillis()-start_time);

}

hash的应用

示例:我们要存储一个用户信息对象数据,包含以下信息: key为用户ID,value为用户对象(姓名,年龄,生日等)如果用普通的key/value结构来存储,主要有以下2种存储方式:

1、将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储 缺点:增加了序列化/反序列化的开销,引入复杂适应系统(Complex adaptive system)修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护。

image-20211031160035668

2、用户信息对象有多少成员就存成多少个key-value对 虽然省去了序列化开销和并发问题,但是用户ID为重复存储。

image-20211031160045876

Redis提供的Hash很好的解决了这个问题,提供了直接存取这个Map成员的接口。Key仍然是用户ID, value是一个Map,这个Map的key是成员的属性名,value是属性值。( 内部实现:Redis Hashd的Value内部有2种不同实现,Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht )。

image-20211031160058515

Instagram内存优化

Instagram可能大家都已熟悉,当前火热的拍照App,月活跃用户3亿。四年前Instagram所存图片3亿多时需要解决一个问题:想知道每一张照片的作者是谁(通过图片ID反查用户UID),并且要求查询速度要相当的块,如果把它放到内存中使用String结构做key-value:

HSET “mediabucket:1155” “1155315” “939”

HGET “mediabucket:1155” “1155315”

“939”

测试:1百万数据会用掉70MB内存,3亿张照片就会用掉21GB的内存。当时(四年前)最好是一台EC2的 high-memory 机型就能存储(17GB或者34GB的,68GB的太浪费了),想把它放到16G机型中还是不行的。

Instagram的开发者向Redis的开发者之一Pieter Noordhuis询问优化方案,得到的回复是使用Hash结构。具体的做法就是将数据分段,每一段使用一个Hash结构存储. 由于Hash结构会在单个Hash元素在不足一定数量时进行压缩存储,所以可以大量节约内存。这一点在上面的String结构里是不存在的。而这个一定数量是由配置文件中的hash-zipmap-max-entries参数来控制的。经过实验,将hash-zipmap-max-entries设置为1000时,性能比较好,超过1000后HSET命令就会导致CPU消耗变得非常大。

HSET “mediabucket:1155” “1155315” “939”

HGET “mediabucket:1155” “1155315”

“939”

测试:1百万消耗16MB的内存。总内存使用也降到了5GB。当然我们还可以优化,去掉mediabucket:key长度减少了12个字节。

HSET “1155” “315” “939”

HGET “1155” “315”

“939”

三、优化案例

1、修改linux中TCP监听的最大容纳数量

/proc/sys/net/core/somaxconn is set to the lower value of 128.

在高并发环境下你需要一个高backlog值来避免慢客户端连接问题。注意Linux内核默默地将这个值减小到/proc/sys/net/core/somaxconn的值,所以需要确认增大somaxconn和tcp_max_syn_backlog两个值来达到想要的效果。 echo 511 > /proc/sys/net/core/somaxconn 注意:这个参数并不是限制redis的最大链接数。如果想限制redis的最大连接数需要修改maxclients,默认最大连接数为10000

2、修改linux内核内存分配策略

错误日志:WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.

To fix this issue add ‘vm.overcommit_memory = 1’ to /etc/sysctl.conf and then reboot or

run the command 'sysctl vm.overcommit_memory=1

redis在备份数据的时候,会fork出一个子进程,理论上child进程所占用的内存和parent是一样的,比如parent占用的内存为8G,这个时候也要同样分配8G的内存给child,如果内存无法负担,往往会造成redis服务器的down机或者IO负载过高,效率下降。所以内存分配策略应该设置为 1(表示内核允许分配所有的物理内存,而不管当前的内存状态如何)。 内存分配策略有三种 可选值:0、1、2。 0, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。 1, 不管需要多少内存,都允许申请。 2, 只允许分配物理内存和交换内存的大小(交换内存一般是物理内存的一半)。

3、关闭Transparent Huge Pages(THP)

THP会造成内存锁影响redis性能,建议关闭

Transparent HugePages :用来提高内存管理的性能

Transparent Huge Pages在32位的RHEL 6中是不支持的

执行命令 echo never > /sys/kernel/mm/transparent_hugepage/enabled

把这条命令添加到这个文件中/etc/rc.local

我看过不少的关于redis的学籍,以及一些学习笔记,虽然都还不错,但是能够从浅深入到源码的却很少,前几天看到的一份来阿里大牛自产的“Redis深度笔记”,起码是我目前看到过的最完善,最有深度的一份笔记了。有需要可以点击文末名片免费领取,无套路。

笔记大概分为以下几个部分:

  • 开篇基础部分

  • 九大应用部分

  • 八大原理部分

  • 三大集群部分

  • 九大拓展部分

  • 七大源码部分

一、开篇基础部分


  1. 开篇:授人以鱼不若授人以鱼-Redis可以用来做什么

  2. 基础:万丈高楼平地起-Redis基础数据结构

二、九大应用部分


  1. 千帆竞发-分布式锁

  2. 缓兵之计-延时队列

  3. 节衣缩食-位图

  4. 四两拨千斤-HyperLogLog

  5. 层峦叠嶂-布隆过滤器

  6. 断尾求生-简单限流

  7. 一毛不拔-漏斗限流

  8. 近水楼台-GeoHash

  9. 大海捞针-Scan

三、八大原理部分


  1. 鞭辟入里-线程IO模型

  2. 交头接耳-通信协议

  3. 未雨绸缪-持久化

  4. 雷厉风行-管道

  5. 同舟共济-事务

  6. 小道消息-PubSub

  7. 开源节流-小对象压缩

最后:学习总结——MyBtis知识脑图(纯手绘xmind文档)

学完之后,若是想验收效果如何,其实最好的方法就是可自己去总结一下。比如我就会在学习完一个东西之后自己去手绘一份xmind文件的知识梳理大纲脑图,这样也可方便后续的复习,且都是自己的理解,相信随便瞟几眼就能迅速过完整个知识,脑补回来。下方即为我手绘的MyBtis知识脑图,由于是xmind文件,不好上传,所以小编将其以图片形式导出来传在此处,细节方面不是特别清晰。但可给感兴趣的朋友提供完整的MyBtis知识脑图原件(包括上方的面试解析xmind文档)

image

除此之外,前文所提及的Alibaba珍藏版mybatis手写文档以及一本小小的MyBatis源码分析文档——《MyBatis源码分析》等等相关的学习笔记文档,也皆可分享给认可的朋友!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

Btis知识脑图原件(包括上方的面试解析xmind文档)

[外链图片转存中…(img-lVyAFa8D-1715134231647)]

除此之外,前文所提及的Alibaba珍藏版mybatis手写文档以及一本小小的MyBatis源码分析文档——《MyBatis源码分析》等等相关的学习笔记文档,也皆可分享给认可的朋友!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
java实现秒杀系统@Controller @RequestMapping("seckill")//url:/模块/资源/{id}/细分 /seckill/list public class SeckillController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private SeckillService seckillService; @RequestMapping(value="/list",method = RequestMethod.GET) public String list(Model model){ //获取列表页 List list=seckillService.getSeckillList(); model.addAttribute("list",list); //list.jsp+model = ModelAndView return "list";//WEB-INF/jsp/"list".jsp } @RequestMapping(value = "/{seckillId}/detail",method = RequestMethod.GET) public String detail(@PathVariable("seckillId") Long seckillId, Model model){ if (seckillId == null){ return "redirect:/seckill/list"; } Seckill seckill = seckillService.getById(seckillId); if (seckill == null){ return "forward:/seckill/list"; } model.addAttribute("seckill",seckill); return "detail"; } //ajax json @RequestMapping(value = "/{seckillId}/exposer", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"}) @ResponseBody public SeckillResult exposer(@PathVariable("seckillId") Long seckillId){ SeckillResult result; try { Exposer exposer =seckillService.exportSeckillUrl(seckillId); result = new SeckillResult(true,exposer); } catch (Exception e) { logger.error(e.getMessage(),e); result = new SeckillResult(false,e.getMessage()); } return result; } @RequestMapping(value = "/{seckillId}/{md5}/execution", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"} ) @ResponseBody public SeckillResult execute(@PathVariable("seckillId")Long seckillId,
如果您使用Java后端Redis中获取SSE消息,并且无法推送消息到客户端,则可能存在以下问题: 1. 消息格式问题:请确保您的SSE消息是以“data:”开头的文本数据,并且遵循SSE规范。您可以在Java中使用类似于以下代码的方式构造SSE消息: ``` String sseMessage = "data: " + message + "\n\n"; ``` 其中,message是您要发送的消息内容。请注意,在消息结尾需要添加两个换行符。 2. 推送代码错误:请确保您使用的是正确的SSE推送代码,并且已正确配置和初始化相关的库和插件。例如,在Java中,您可以使用Spring Framework的SseEmitter类进行SSE推送。以下是一个简单的示例代码: ``` @RequestMapping("/stream") public SseEmitter stream() { final SseEmitter emitter = new SseEmitter(); // 从Redis中获取SSE消息,并将其推送到客户端 redisClient.onMessage((channel, message) -> { String sseMessage = "data: " + message + "\n\n"; emitter.send(sseMessage); }); return emitter; } ``` 请注意,在使用SseEmitter进行SSE推送时,您需要在客户端与服务器之间保持长时间开放的连接,以便持续地推送消息。 3. 连接问题:请确保您的客户端与服务器之间的连接仍处于活动状态,并且网络连接正常。如果客户端断开连接,则您需要在服务器端检测到并关闭相应的SSE连接。 4. 安全问题:请确保您的SSE连接已正确配置,并且使用了适当的安全措施,例如使用HTTPS协议,或者对SSE连接进行身份验证和授权。 如果您仍然无法解决问题,请尝试检查服务器端和客户端的日志,以获取更多的错误信息和调试信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值