先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip204888 (备注网络安全)
正文
- 再比如,某个字段值非常集中,90%都是1,剩下10%可能是2,3,4…
进一步的,那如果不符合上面所有的索引失效的情况,但是mysql还是不使用对应的索引,是为啥呢?这个跟mysql的sql优化有关,mysql会在sql优化的时候自己选择合适的索引,很可能是mysql自己的选择算法算出来使用这个索引不会提升性能,所以就放弃了。这种情况,可以使用force index 关键字强制使用索引(建议修改前先实验一下,是不是真的会提升查询效率):
select name,code from student force index(XXXXXX) where name = '天才'
其中xxxx是索引名。
1.4 join过多 or 子查询过多
我把join过多 和子查询过多放在一起说了。一般来说,不建议使用子查询,可以把子查询改成join来优化。同时,join关联的表也不宜过多,一般来说2-3张表还是合适的。具体关联几张表比较安全是需要具体问题具体分析的,如果各个表的数据量都很少,几百条几千条,那么关联的表的可以适当多一些,反之则需要少一些。
另外需要提到的是,在大多数情况下join是在内存里做的,如果匹配的量比较小,或者join_buffer设置的比较大,速度也不会很慢。但是,当join的数据量比较大的时候,mysql会采用在硬盘上创建临时表的方式进行多张表的关联匹配,这种显然效率就极低,本来磁盘的IO就不快,还要关联。
一般遇到这种情况的时候就建议从代码层面进行拆分,在业务层先查询一张表的数据,然后以关联字段作为条件查询关联表形成map,然后在业务层进行数据的拼装。一般来说,索引建立正确的话,会比join快很多,毕竟内存里拼接数据要比网络传输和硬盘IO快得多。
1.5 in的元素过多
这种问题,如果只看代码的话不太容易排查,最好结合监控和数据库日志一起分析。如果一个查询有in,in的条件加了合适的索引,这个时候的sql还是比较慢就可以高度怀疑是in的元素过多。一旦排查出来是这个问题,解决起来也比较容易,不过是把元素分个组,每组查一次。想再快的话,可以再引入多线程。
进一步的,如果in的元素量大到一定程度还是快不起来,这种最好还是有个限制
select id from student where id in (1,2,3 ...... 1000) limit 200
当然了,最好是在代码层面做个限制
if (ids.size() > 200) {
throw new Exception("单次查询数据量不能超过200");
}
1.6 单纯的数据量过大
这种问题,单纯代码的修修补补一般就解决不了了,需要变动整个的数据存储架构。或者是对底层mysql分表或分库+分表;或者就是直接变更底层数据库,把mysql转换成专门为处理大数据设计的数据库。这种工作是个系统工程,需要严密的调研、方案设计、方案评审、性能评估、开发、测试、联调,同时需要设计严密的数据迁移方案、回滚方案、降级措施、故障处理预案。除了以上团队内部的工作,还可能有跨系统沟通的工作,毕竟做了重大变更,下游系统的调用接口的方式有可能会需要变化。
出于篇幅的考虑,这个不再展开了,笔者有幸完整参与了一次亿级别数据量的数据库分表工作,对整个过程的复杂性深有体会,后续有机会也会分享出来。
2、业务逻辑复杂
2.1 循环调用
这种情况,一般都循环调用同一段代码,每次循环的逻辑一致,前后不关联。比如说,我们要初始化一个列表,预置12个月的数据给前端:
List<Model> list = new ArrayList<>();
for(int i = 0 ; i < 12 ; i ++) {
Model model = calOneMonthData(i); // 计算某个月的数据,逻辑比较复杂,难以批量计算,效率也无法很高
list.add(model);
}
这种显然每个月的数据计算相互都是独立的,我们完全可以采用多线程方式进行:
// 建立一个线程池,注意要放在外面,不要每次执行代码就建立一个,具体线程池的使用就不展开了
public static ExecutorService commonThreadPool = new ThreadPoolExecutor(5, 5, 300L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(10), commonThreadFactory, new ThreadPoolExecutor.DiscardPolicy());
// 开始多线程调用
List<Future<Model>> futures = new ArrayList<>();
for(int i = 0 ; i < 12 ; i ++) {
Future<Model> future = commonThreadPool.submit(() -> calOneMonthData(i););
futures.add(future);
}
// 获取结果
List<Model> list = new ArrayList<>();
try {
for (int i = 0 ; i < futures.size() ; i ++) {
list.add(futures.get(i).get());
}
} catch (Exception e) {
LOGGER.error("出现错误:", e);
}
2.2 顺序调用
如果不是类似上面循环调用,而是一次次的顺序调用,而且调用之间没有结果上的依赖,那么也可以用多线程的方式进行,例如:
代码上看:
A a = doA();
B b = doB();
C c = doC(a, b);
D d = doD(c);
E e = doE(c);
return doResult(d, e);
那么可用CompletableFuture解决
CompletableFuture<A> futureA = CompletableFuture.supplyAsync(() -> doA());
CompletableFuture<B> futureB = CompletableFuture.supplyAsync(() -> doB());
CompletableFuture.allOf(futureA,futureB) // 等a b 两个任务都执行完成
C c = doC(futureA.join(), futureB.join());
CompletableFuture<D> futureD = CompletableFuture.supplyAsync(() -> doD(c));
CompletableFuture<E> futureE = CompletableFuture.supplyAsync(() -> doE(c));
CompletableFuture.allOf(futureD,futureE) // 等d e两个任务都执行完成
return doResult(futureD.join(),futureE.join());
这样A B 两个逻辑可以并行执行,D E两个逻辑可以并行执行,最大执行时间取决于哪个逻辑更慢。
3、线程池设计不合理
有的时候,即使我们使用了线程池让任务并行处理,接口的执行效率仍然不够快,这种情况可能是怎么回事呢?
这种情况首先应该怀疑是不是线程池设计的不合理。我觉得这里有必要回顾一下线程池的三个重要参数:核心线程数、最大线程数、等待队列。这三个参数是怎么打配合的呢?当线程池创建的时候,如果不预热线程池,则线程池中线程为0。当有任务提交到线程池,则开始创建核心线程。
当核心线程全部被占满,如果再有任务到达,则让任务进入等待队列开始等待。
如果队列也被占满,则开始创建非核心线程运行。
如果线程总数达到最大线程数,还是有任务到达,则开始根据线程池抛弃规则开始抛弃。
那么这个运行原理与接口运行时间有什么关系呢?
- 核心线程设置过小:核心线程设置过小则没有达到并行的效果
- 线程池公用,别的业务的任务执行时间太长,占用了核心线程,另一个业务的任务到达就直接进入了等待队列
- 任务太多,以至于占满了线程池,大量任务在队列中等待
在排查的时候,只要找到了问题出现的原因,那么解决方式也就清楚了,无非就是调整线程池参数,按照业务拆分线程池等等。
4、锁设计不合理
锁设计不合理一般有两种:锁类型使用不合理 or 锁过粗。
锁类型使用不合理的典型场景就是读写锁。也就是说,读是可以共享的,但是读的时候不能对共享变量写;而在写的时候,读写都不能进行。在可以加读写锁的时候,如果我们加成了互斥锁,那么在读远远多于写的场景下,效率会极大降低。
锁过粗则是另一种常见的锁设计不合理的情况,如果我们把锁包裹的范围过大,则加锁时间会过长,例如:
public synchronized void doSome() { File f = calData(); uploadToS3(f); sendSuccessMessage();}
这块逻辑一共处理了三部分,计算、上传结果、发送消息。显然上传结果和发送消息是完全可以不加锁的,因为这个跟共享变量根本不沾边。因此完全可以改成:
public void doSome() { File f = null; synchronized(this) { f = calData(); } uploadToS3(f); sendSuccessMessage();}
5、机器问题(fullGC,机器重启,线程打满)
造成这个问题的原因非常多,笔者就遇到了定时任务过大引起fullGC,代码存在线程泄露引起RSS内存占用过高进而引起机器重启等待诸多原因。需要结合各种监控和具体场景具体分析,进而进行大事务拆分、重新规划线程池等等工作
6、万金油解决方式
还有兄弟不知道网络安全面试可以提前刷题吗?费时一周整理的160+网络安全面试题,金九银十,做网络安全面试里的显眼包!
王岚嵚工程师面试题(附答案),只能帮兄弟们到这儿了!如果你能答对70%,找一个安全工作,问题不大。
对于有1-3年工作经验,想要跳槽的朋友来说,也是很好的温习资料!
【完整版领取方式在文末!!】
93道网络安全面试题
内容实在太多,不一一截图了
黑客学习资源推荐
最后给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
1️⃣零基础入门
① 学习路线
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
② 路线对应学习视频
同时每个成长路线对应的板块都有配套的视频提供:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
//img-blog.csdnimg.cn/874ad4fd3dbe4f6bb3bff17885655014.png#pic_center)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
[外链图片转存中…(img-92hk7Apk-1713606148183)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!