
获得徽章 1
- #青训营笔记创作活动#
2023/2/12 打卡 day12
502问题怎么排查?
HTTP状态码
TCP是基于数据流的协议,传输数据时,并不会为每个消息加入数据边界,直接使用裸的TCP进行数据传输会有"粘包/拆包"问题。因此需要用特地的协议格式去对数据进行解析。于是在此基础上设计了HTTP协议。
于是就需要设计一套HTTP状态码,用来标识这次HTTP请求响应流程是否正常。通过这个可以影响浏览器的行为。比方说一切正常,那服务端返回个200状态码,前端收到后,可以放心使用响应的数据。但如果服务端发现客户端发的东西异常,就响应个4xx状态码,意思是这是个客户端的错误,4xx里头的xx可以根据错误的类型,再细分成各种码,比如401是客户端没权限,404是客户端请求了一个根本不存在的网页。反过来,如果是服务器有问题,就返回5xx状态码。一般情况下5xx的状态码其实并不是服务器返回给客户端的。它们是由网关返回的,常见的网关,比如nginx。
屏蔽掉具体有哪些服务器的代理方式就是所谓的反向代理。反过来,屏蔽掉具体有哪些客户端的代理方式,就是所谓的正向代理。而这个中间层的角色,一般由nginx这类网关来充当。
- HTTP状态码用来表示响应结果的状态,其中200是正常响应,4xx是客户端错误,5xx是服务端错误。
- 客户端和服务端之间加入nginx,可以起到反向代理和负载均衡的作用,客户端只管向nginx请求数据,并不关心这个请求具体由哪个服务器来处理。
- 后端服务端应用如果发生崩溃,nginx在访问服务端时会收到服务端返回的RST报文,然后给客户端返回502报错。502并不是服务端应用发出的,而是nginx发出的。因此发生502时,后端服务端很可能没有没有相关的502日志,需要在nginx侧才能看到这条502日志。
- 如果发现502,优先通过监控排查服务端应用是否发生过崩溃重启,如果是的话,再看下是否留下过崩溃堆栈日志,如果没有日志,看下是否可能是oom或者是其他原因导致进程主动退出。如果进程也没崩溃过,去排查下nginx的日志,看下是否将请求打到了某个不知名IP端口上。展开评论点赞 - #青训营笔记创作活动#
2023/2/11 打卡day11
如果把网络原理倒过来看,从无到有,一切都清晰了(上)
从单机到互联:本质是通信问题
数据传输方式:电路交换、报文交换、分组交换
电路交换:
最简单的连接两台相隔遥远的计算机的办法是分配一条专用通信(也就是一条专用的物理通路),而这就是电路传输方式。在电路交换中如果多台计算机之间互联,两两之间互联都需要拉线,那需要的电线也太多了。
于是就来到了两个思想,一个是转发,另一个是标识;它们是网络设计的核心问题,因为它们是一个网络扩大的基础。
转发的思想其实很简单,试想我们有A、B、C三台计算机,A和C并没有相连,而是经过了B。那么A计算机可以不可以先发到B计算机,再让B计算机帮我们转发C计算机呢。
标识的思想是,如果只是两台计算机,那么我们很清楚通信双方就是A在和B之间的通信(也就是相当明确数据是谁发送,以及是谁接收)。因此有了 MAC 地址
集线器(Hub)
计算机工程领域的任何问题都可以通过增加一个中间层来解决。所以我们可以加多一个中间设备,也就是集线器(Hub)。集线器是一层设备,(对应OSI网络模型,集线器就是工作在物理层),集线器将每台计算机之间连接在一起,所以它的每个接口仅仅简单地转发比特,意味着收到即转发(也就是收到1转会发1,收到0就转发0)。
交换机
交换机属于二层设备(对应OSI网络模型,也就是在数据链路层)。交换机比起集线器,实现了数据的全双工的通信,例如:A计算机在发送的时候,同时也可以进行数据的接收,在这个链路上的数据也不再会产生冲突。
报文交换
那么为了解决电路交换的“占线”问题,报文交换将每个用户发送的数据拆分成多个更小的部分数据,这些更小的数据携带着标识,起始点和目的地。那么不管是多少用户是否占着线,就需要存储-转发,只要拼凑汇聚成一个完整的数据。
分组交换
分组交换的思想源于报文交换,也采用存储转发的原理,但不同的是分组交换的最小信息单位是分组,而报文交换则是一个个报文。分组加速了数据在网络中的传输,一个分组的存储与前一个分组转发可以并行,所以本质分组交换也是存储转发,可以说让报文更加有组织,转发也更加迅速。
路由器是三层设备(对应OSI网络模型在网络层),所以路由器所连接的范围更广,网络和网络之间的连接就是通过路由器展开评论点赞 - #青训营笔记创作活动#
2023/2/10 打卡 day10
优秀后端都应该具备的开发好习惯
1.注释尽可能全面,写有意义的方法注释
对于接口方法的注释,应该包含详细的入参和结果说明,有异常抛出的情况也要详细叙述;类的注释应该包含类的功能说明、作者和修改者。;如果是业务逻辑很复杂的代码,真的非常有必要写清楚注释。
2.项目拆分合理的目录结构
如果服务过多,应该根据不同的业务进行划分,比如订单、登陆、积分等等。也可以根据不同的业务划分模块,比如建一个moudles包,然后按订单、登陆等业务划分,每个业务都有自己的controller、service、mapper、entity。
3. 不在循环里远程调用、或者数据库操作,优先考虑批量进行。远程操作或者数据库操作都是比较耗网络、IO资源的,所以尽量不在循环里远程调用、不在循环里操作数据库,能批量一次性查回来尽量不要循环多次去查。
4. 封装方法形参
如果你的方法参数过多,要封装一个对象出来。
5. 封装通用模板
6. 封装复杂的逻辑判断条件
7. 保持优化性能的嗅觉
比如避免创建非必要的对象、异步处理、使用缓冲流,减少IO操作等等。
8. 可变参数的配置化处理
比如用户多少天没登录注销、运营活动,不同节日红包皮肤切换、订单多久没付款就删除等等。对于这些可变的参数,不用该直接写死在代码。优秀的后端,要做配置化处理,你可以把这些可变参数,放到数据库一个配置表里面,也可以放到项目的配置文件或者apollo上。
9. 会总结并使用工具类。
我们既要会用工具类,更要学会自己去总结工具类。比如去文件处理工具类、日期处理工具类等等
10. 控制方法函数复杂度
你的方法不要写得太复杂,逻辑不要混乱,也不要太长。一个函数不能超过80行。写代码不仅仅是能跑就行,而是为了以后更好的维护。
11. 在finally块中对资源进行释放
12.把日志打印好
一般情况,方法入参、出参需要打印日志,异常的时候,也要打印日志等等
13. 考虑异常,处理好异常
14. 考虑系统、接口的兼容性
15. 代码采取措施避免运行时错误
优秀的后端开发,应该在编写代码阶段,就采取措施,避免运行时错误,如数组边界溢出,被零整除,空指针等运行时错误。展开评论点赞 - #青训营笔记创作活动#
2023/2/9 打卡 day9
MySQL 整体架构:
当一个客户端尝试与MySQL建立连接时,MySQL内部都会派发一条线程负责处理该客户端接下来的所有工作。而数据库的连接层负责的就是所有客户端的接入工作,MySQL的连接一般都是基于TCP/IP协议建立网络连接,因此凡是可以支持TCP/IP的语言,几乎都能与MySQL建立连接。
虽然MySQL是基于TCP/IP协议栈实现的连接建立工作,但并非使用HTTP协议建立连接的,一般建立连接的具体协议,都会根据不同的客户端实现,如jdbc、odbc...这类的。
Connection Pool:所有的客户端连接都需要一条线程去维护,而线程资源无论在哪里都属于宝贵资源,因此不可能无限量创建,所以这里的连接池就相当于Tomcat中的线程池,主要是为了复用线程、管理线程以及限制最大连接数的。连接池的最大线程数可以通过参数max-connections来控制,如果到来的客户端连接超出该值时,新到来的连接都会被拒绝,关于最大连接数的一些命令主要有两条:
show variables like '%max_connections%';:查询目前DB的最大连接数。
set GLOBAL max_connections = 200;:修改数据库的最大连接数为指定值。
系统服务层:MySQL大多数核心功能都位于这一层,包括客户端SQL请求解析、语义分析、查询优化、缓存以及所有的内置函数(例如:日期、时间、统计、加密函数...),所有跨引擎的功能都在这一层实现,譬如存储过程、触发器和视图等一系列服务。
存储引擎层:存储引擎也可以理解成MySQL最重要的一层,在前面的服务层中,聚集了MySQL所有的核心逻辑操作,而引擎层则负责具体的数据操作以及执行工作。
文件系统层:这一层则是MySQL数据库的基础,本质上就是基于机器物理磁盘的一个文件系统,其中包含了配置文件、库表结构文件、数据文件、索引文件、日志文件等各类MySQL运行时所需的文件,这一层的功能比较简单,也就是与上层的存储引擎做交互,负责数据的最终存储与持久化工作。展开评论点赞 - #青训营笔记创作活动#
2023/2/8 打卡 day8
写出漂亮代码的45个小技巧
1、规范命名
2、规范代码格式
3、写好代码注释
4、try catch 内部代码抽成一个方法
5、方法别太长
6、抽取重复代码
7、多用return
8、if条件表达式不要太复杂
9、优雅地参数校验
10、统一返回值
11、统一异常处理
12、尽量不传递null值
13、尽量不返回null值
14、日志打印规范
15、统一类库
16、尽量使用工具类
17、尽量不要重复造轮子
18、类和方法单一职责
19、尽量使用聚合/组合代替继承
20、使用设计模式优化代码
21、不滥用设计模式
22、面向接口编程
23、经常重构旧的代码
24、null值判断
25、pojo类重写toString方法
26、魔法值用常量表示
27、资源释放写到finally
28、使用线程池代替手动创建线程
29、线程设置名称
30、涉及线程间可见性加volatile
31、考虑线程安全问题
32、慎用异步
33、减小锁的范围
34、有类型区分时定义好枚举
35、远程接口调用设置超时时间
36、集合使用应当指明初始化大小
37、尽量不要使用BeanUtils来拷贝属性
38、使用StringBuilder进行字符串拼接
39、@Transactional应指定回滚的异常类型
40、谨慎方法内部调用动态代理的方法
41、需要什么字段select什么字段
42、不循环调用数据库
43、用业务代码代替多表join
44、装上阿里代码检查插件
45、及时跟同事沟通展开评论点赞 - #青训营笔记创作活动#
2023/2/6 打卡 day7
用UDP就一定比用TCP快吗?什么情况下用UDP会比用TCP慢?
socket就像是一个电话或者邮箱(邮政的信箱)。当你想要发送消息的时候,拨通电话或者将信息塞到邮箱里,socket内核会自动完成将数据传给对方的这个过程。基于socket我们可以选择使用TCP或UDP协议进行通信。
socket 创建:fd = socket(AF_INET, 具体协议,0);
"具体协议",如果传入的是SOCK_STREAM,是指使用字节流传输数据,说白了就是TCP协议(面向连接,可靠的,基于字节流);如果传入的是SOCK_DGRAM,是指使用数据报传输数据,也就是UDP协议(无连接,不可靠的,基于消息报)。
对于异常情况的处理:
重传机制:对于TCP,它会给发出的消息打上一个编号(sequence),接收方收到后回一个确认(ack)。发送方可以通过ack的数值知道接收方收到了哪些equence的包。如果长时间等不到对方的确认,TCP就会重新发一次消息,这就是所谓的重传机制。
TCP为了实现可靠性,引入了重传机制、流量控制、滑动窗口、拥塞控制、分段以及乱序重排机制。而UDP则没有实现,因此一般来说TCP比UDP快。
TCP是面向连接的协议,而UDP是无连接的协议。这里的"连接"其实是,操作系统内核在两端代码里维护的一套复杂状态机。
大部分项目,会在基于UDP的基础上,模仿TCP,实现不同程度的可靠性机制。比如王者农药用的KCP其实就在基于UDP在应用层里实现了一套重传机制。
对于UDP+重传的场景,如果要传超大数据包,并且没有实现分段机制的话,那数据就会在IP层分片,一旦丢包,那就需要重传整个超大数据包。而TCP则不需要考虑这个,内部会自动分段,丢包重传分段就行了。这种场景下,其实TCP更快。展开评论点赞 - #青训营笔记创作活动#
2023/2/5 打卡 day6
Kafka 科普
消息系统:Kafka 和传统的消息系统(也称作消息中间件)都具备系统解耦、冗余存储、流量削峰、缓冲、异步通信、扩展性、可恢复性等功能。与此同时,Kafka 还提供了大多数消息系统难以实现的消息顺序性保障及回溯消费的功能。
存储系统:Kafka 把消息持久化到磁盘,相比于其他基于内存存储的系统而言,有效地降低了数据丢失的风险。也正是得益于 Kafka 的消息持久化功能和多副本机制,我们可以把 Kafka 作为长期的数据存储系统来使用,只需要把对应的数据保留策略设置 为“永久”或启用主题的日志压缩功能即可。
流式处理平台:Kafka 不仅为每个流行的流式处理框架提供了可靠的数据来源,还提供了一个完整的流式处理类库,比如窗口、连接、变换和聚合等各类操作。
一个典型的 Kafka 体系架构包括若干 Producer、若干 Broker、若干 Consumer,以及一个 ZooKeeper 集群,如图所示。其中 ZooKeeper 是 Kafka 用来负责集群元数据的管理、控制器 的选举等操作的。Producer 将消息发送到 Broker,Broker 负责将收到的消息存储到磁盘中,而 Consumer 负责从 Broker 订阅并消费消息。
整个 Kafka 体系结构中引入了以下 3 个术语。
Producer:生产者,也就是发送消息的一方。生产者负责创建消息,然后将其投递到 Kafka 中。
Consumer:消费者,也就是接收消息的一方。消费者连接到 Kafka 上并接收消息,进 而进行相应的业务逻辑处理。
Broker:服务代理节点。对于 Kafka 而言,Broker 可以简单地看作一个独立的 Kafka 服务节点或 Kafka 服务实例。大多数情况下也可以将 Broker 看作一台 Kafka 服务器,前提是这台服务器上只部署了一个 Kafka 实例。一个或多个 Broker 组成了一个 Kafka 集群。一般而言, 我们更习惯使用首字母小写的 broker 来表示服务代理节点。展开评论点赞 - #第五届青训营阅读打卡#
2023/2/4 打卡 day5
学习 websocket 协议
看起来服务器主动发消息给客户端的场景,是怎么做到的?
使用HTTP不断轮询,最常见的解决方案是,网页的前端代码里不断定时发HTTP请求到服务器,服务器收到请求后给客户端响应消息。最常见的场景就是扫码登录。
长轮询,如果我们的HTTP请求将超时设置的很大,比如30s,在这30s内只要服务器收到了扫码请求,就立马返回给客户端网页。如果超时,那就立马发起下一次请求。这样就减少了HTTP请求的个数。像这种发起一个请求,在较长时间内等待服务器响应的机制,就是所谓的长轮询机制。我们常用的消息队列RocketMQ中,消费者去取数据时,也用到了这种方式。
TCP协议本身是全双工的,但我们最常用的HTTP1.1,虽然是基于TCP的协议,但它是半双工的,对于大部分需要服务器主动推送数据到客户端的场景,都不太友好,因此我们需要使用支持全双工的websocket协议。
在HTTP1.1里。只要客户端不问,服务端就不答。基于这样的特点,对于登录页面这样的简单场景,可以使用定时轮询或者长轮询的方式实现服务器推送(comet)的效果。
对于客户端和服务端之间需要频繁交互的复杂场景,比如网页游戏,都可以考虑使用websocket协议。
websocket和socket几乎没有任何关系,只是叫法相似。
正因为各个浏览器都支持HTTP协议,所以websocket会先利用HTTP协议加上一些特殊的header头进行握手升级操作,升级成功后就跟HTTP没有任何关系了,之后就用websocket的数据格式进行收发数据。展开评论点赞 - #青训营笔记创作活动#
2023/2/3 打卡day4
学习 DHCP 协议
插上网线之后,获得IP的方式主要有两种。
第一种是,自己手动在电脑里配。在选择手动配置之后,除了IP地址还需要配上子网掩码和路由器的地址。
第二种获取IP的方式,DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)。通过DHCP,在联网之后可以自动获取到本机需要的IP地址,子网掩码还有路由器地址。
DHCP的工作原理就是向某个管IP分配的服务器,也就是DHCP服务器,申请IP地址。整个操作流程分为 4 个阶段。
step1-DHCP Discover:在联网时,本机由于没有IP,也不知道DHCP服务器的IP地址是多少,所以根本不知道该向谁发起请求,于是索性选择广播,向本地网段内所有人发出消息,询问"谁能给个IP用用"。
step2-DHCP Offer:不是DHCP服务器的机子会忽略你的广播消息,而DHCP服务器收到消息后,会在自己维护的一个IP池里拿出一个空闲IP,通过广播的形式给回你的电脑。
step3-DHCP Request:你的电脑在拿到IP后,再次发起广播,就说"这个IP我要了"。
step4-DHCP ACK:DHCP服务器此时再回复你一个ACK,意思是"ok的"。你就正式获得这个IP在一段时间(比如24小时)里的使用权了。后续只要IP租约不过期,就可以一直用这个IP进行通信了。
电脑插上网线,联网后会通过DHCP协议动态申请一个IP,同时获得子网掩码,路由器地址等信息。
DHCP分为四个阶段,分别是 Discover,Offer, Request和ACK。
如果曾经连过这个网,机器会记录你上次使用的IP,再次连接时优先使用原来的那个IP,因此只需要经历第三第四阶段。
DHCP是应用层协议,考虑到需要支持广播功能,底层使用的是UDP协议,而不是TCP协议。
DHCP分配下来的IP是有可能跟某台手动配置的IP地址重复的。
DHCP得到IP之后还会发3次无偿ARP通告,在确认没有冲突后开始使用这个IP。展开赞过评论1 - #青训营笔记创作活动#
2023/2/2 打卡 day3juejin.cn
最左匹配原则就是指在联合索引中,如果你的 SQL 语句中用到了联合索引中的最左边的索引,那么这条 SQL 语句就可以利用这个联合索引去进行匹配。
最左匹配原则顾名思义:最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配。最左缀匹配原则的最重要的就是联合索引的第一个字段。
select * 不是造成索引失效的直接原因 大部分原因是 where 后边条件的问题 但是还是尽量少去使用select * 多少还是会有影响的。
范围查找有概率索引失效但是在特定的情况下会生效 范围小就会使用 也可以理解为 返回结果集小就会使用索引
只要是影响到索引列的值,索引就会失效(函数/计算)
索引的时候和查询范围关系也很大,范围过大造成索引没有意义从而失效
在 WHERE 子句中,如果在 OR 前的条件列是索引列,而在 OR 后的条件列不是索引列,那么索引会失效。从执行计划的结果看,是走了全表扫描。优化方式就是在 Or 两边的字段都加上索引。
使用 in 不是一定会造成全表扫描的,in 肯定会走索引,但是当 in 的取值范围较大时会导致索引失效,走全表扫描(not in 同理)。
在 Order By 的情况下 走全表扫描反而是更好的选择。展开评论点赞