1. session里存啥 session和cookie区别
在Web开发中,Session和Cookie是两种常用的机制,用于在服务器和客户端之间存储和传递数据。
Session是服务器端存储用户信息的一种机制。当用户第一次访问服务器时,服务器会为该用户创建一个唯一的Session ID,并将该ID存储在Cookie中发送给客户端。客户端在后续的请求中会携带该Cookie,服务器通过Session ID可以找到对应的Session数据。服务器可以在Session中存储用户的登录状态、购物车信息等数据,以便在用户不同请求之间保持状态的一致性。Session数据存储在服务器端,相对来说更安全,但会占用服务器的内存资源。
Cookie是存储在客户端的一小段文本信息。服务器在响应中通过Set-Cookie头部将Cookie信息发送给客户端,客户端会将Cookie保存起来,并在后续的请求中携带该Cookie发送给服务器。Cookie可以存储一些用户偏好设置、登录凭证等信息。由于Cookie存储在客户端,所以可以在不同的浏览器和设备之间共享,但也存在一定的安全风险,比如可能被恶意篡改或窃取。
Session和Cookie的区别主要在于存储位置和安全性。Session数据存储在服务器端,相对安全但占用服务器资源;Cookie存储在客户端,方便共享但存在一定的安全风险。
专栏面经下载
2. redis和mysql双写一致性为什么删缓存而不是更新缓存
主要有以下几个原因:
- 数据一致性:当数据发生更新时,为了保证数据的一致性,需要先更新数据库,再更新缓存。如果先更新缓存,再更新数据库,可能会导致数据库更新失败或发生异常,导致数据库和缓存之间的数据不一致。而如果选择删除缓存,下次请求时会重新从数据库中读取最新数据并更新缓存,确保了数据的一致性。
- 并发写入:在高并发的场景下,多个请求同时写入数据库可能会导致并发冲突和数据不一致的问题。如果先更新缓存,再更新数据库,可能会导致多个请求同时读取到旧的缓存数据并同时写入数据库,造成数据冲突。而删除缓存后,下次请求会重新从数据库读取最新数据并更新缓存,避免了并发写入的问题。
- 缓存更新成本:更新缓存需要进行网络通信和缓存的写入操作,相对于删除缓存来说,更新缓存的成本更高。而删除缓存后,下次请求会重新从数据库读取最新数据并更新缓存,可以减少缓存更新的成本。
删除缓存后,下次请求会重新从数据库读取最新数据并更新缓存,可能会对系统的性能产生一定的影响,因为需要进行数据库查询和缓存写入的操作。因此,在实际应用中,需要根据具体的业务场景和性能需求来选择适合的缓存策略。
3. 布隆过滤器会不会比较耗内存,添加数据怎么办,删除数据怎么办
布隆过滤器是一种用于快速判断一个元素是否存在于集合中的数据结构,它的优点是查询效率高且占用内存较少。然而,布隆过滤器也存在一些限制和操作上的考虑。
- 内存消耗:布隆过滤器的内存消耗主要取决于预期的误判率和要存储的元素数量。误判率越低,所需的内存空间就越大。一般情况下,布隆过滤器的内存消耗相对较小,但随着元素数量的增加,内存占用也会逐渐增加。
- 添加数据:向布隆过滤器添加数据时,需要对元素进行哈希计算,并将对应的位标记为1。如果哈希冲突较多,可能会导致位的重复标记,进而影响误判率。在添加数据时,可以适当调整布隆过滤器的容量和哈希函数的数量,以平衡误判率和内存消耗。
- 删除数据:布隆过滤器本身不支持直接删除已添加的元素,因为删除一个元素可能会影响其他元素的判断结果。如果需要删除元素,一种常见的做法是使用计数器或其他数据结构辅助记录元素的添加次数,然后在判断元素是否存在时,根据计数器的值进行判断。当计数器为0时,可以认为元素不存在。
需要注意的是,布隆过滤器在判断元素是否存在时,可能存在一定的误判率。因此,在使用布隆过滤器时,需要根据具体的应用场景和需求来选择合适的误判率和内存消耗。
4. 解决缓存穿透其他方法
访问一个缓存和数据库都不存在的 key,此时会直接打到数据库上,并且查不到数据,没法写缓存,所以下一次同样会打到数据库上。此时,缓存起不到作用,请求每次都会走到数据库,流量大时数据库可能会被打挂。此时缓存就好像被“穿透”了一样,起不到任何作用。
解决方案:
1、**接口校验。**在正常业务流程中可能会存在少量访问不存在 key 的情况,但是一般不会出现大量的情况,所以这种场景最大的可能性是遭受了非法攻击。可以在最外层先做一层校验:用户鉴权、数据合法性校验等,例如商品查询中,商品的ID是正整数,则可以直接对非正整数直接过滤等等。
2、缓存空值。当访问缓存和DB都没有查询到值时,可以将空值写进缓存,但是设置较短的过期时间,该时间需要根据产品业务特性来设置。
3、布隆过滤器。使用布隆过滤器存储所有可能访问的 key,不存在的 key 直接被过滤,存在的 key 则再进一步查询缓存和数据库。
5. 缓存击穿解决方案,抛开分布式的话如何解决
缓存击穿:某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库。
- 设置热点数据永不过期:对于一些热点数据,可以将其缓存设置为永不过期,确保即使缓存失效,也能够从缓存中获取到数据。这样可以避免热点数据失效后,大量请求直接访问数据库。
- 加锁机制:在缓存失效的瞬间,可以使用互斥锁(如分布式锁)来保证只有一个请求能够访问数据库,其他请求等待结果。当第一个请求从数据库中获取到数据后,更新缓存并释放锁,其他请求再从缓存中获取数据。
- 缓存预热:在系统启动或者定时任务中,将热点数据预先加载到缓存中。这样可以避免在热点数据失效时,大量请求直接访问数据库,而是直接从缓存中获取数据。
- 异步更新缓存:在数据更新时,先更新数据库,然后异步更新缓存。这样可以保证数据的一致性,同时减少对数据库的访问延迟。
- 限流和熔断:对请求进行限流和熔断处理,当请求量过大时,可以直接拒绝请求或者返回默认结果,避免对数据库造成过大的压力。
6. 给消息队列发消息失败了怎么办
当给消息队列发送消息失败时,可以采取以下几种处理方式:
- 重试发送:首先,可以尝试重新发送消息。消息队列通常提供了重试机制,可以设置重试次数和重试间隔。在发送失败后,可以根据重试策略进行自动或手动的重试操作,直到消息发送成功或达到最大重试次数。
- 消息持久化:如果消息发送失败,可以将消息持久化到本地或者其他存储介质中,以便稍后进行重试。在持久化时,需要注意保证消息的唯一性和顺序性,避免重复发送或乱序发送。
- 错误日志记录:记录发送失败的消息和相关错误信息到日志中,以便后续进行排查和处理。错误日志可以包含发送失败的消息内容、发送时间、错误码等信息,有助于定位问题和进行故障排除。
- 监控和报警:建立监控系统,实时监控消息队列的发送状态和错误情况。当发现消息发送失败时,及时触发报警机制,通知相关人员进行处理和修复。
- 容错处理:在设计系统时,可以考虑引入容错机制,例如使用备份队列或者消息重放机制。当主队列发送失败时,可以将消息发送到备份队列,或者通过消息重放机制重新发送消息,以确保消息的可靠性。
需要根据具体的业务场景和消息队列的特性选择合适的处理方式。同时,也要注意监控和及时处理发送失败的消息,以保证系统的稳定性和可靠性。
7. 限流是针对什么进行限流
限流是一种流量控制的手段,用于限制系统或服务的请求流量,以保护系统免受过载或恶意攻击的影响。限流可以针对以下几个方面进行限制:
- 请求频率限流:限制单位时间内的请求次数或请求速率。例如,限制每秒钟的请求次数不超过某个阈值,或者限制每分钟的请求速率不超过某个阈值。这种限流方式可以防止系统被过多的请求压垮,保证系统的稳定性和可用性。
- 并发连接限流:限制同时连接到系统的请求数量。通过设置最大并发连接数,可以防止系统因为过多的并发请求而资源耗尽或崩溃。这种限流方式适用于需要控制系统负载和资源消耗的场景。
- API接口限流:对特定的API接口进行限流。可以根据接口的重要性、资源消耗情况、用户权限等因素,设置不同的限流策略。这种限流方式可以保护重要接口免受滥用或恶意攻击,确保接口的可用性和稳定性。
- IP限流:对特定IP地址进行限流。可以根据IP地址的访问频率、访问行为等进行限制,防止某个IP地址对系统进行恶意攻击、爬虫行为或者过多的请求。这种限流方式可以保护系统免受恶意访问的影响。
限流的目的是为了保护系统的稳定性、可用性和安全性,防止系统被过载或恶意攻击。具体的限流策略和方式需要根据系统的实际情况和需求进行选择和配置。
8. docker实现原理
Docker 是一种开源的容器化平台,它的实现原理主要包括以下几个方面:
- 命名空间(Namespaces):Docker 使用 Linux 的命名空间技术,包括 PID 命名空间、网络命名空间、挂载命名空间等,通过隔离进程、网络、文件系统等资源,使得每个容器拥有独立的运行环境。
- 控制组(Cgroups):Docker 使用 Linux 的控制组技术,通过限制和管理资源的使用,如 CPU、内存、磁盘、网络带宽等,实现对容器资源的控制和隔离。
- 联合文件系统(UnionFS):Docker 使用联合文件系统来构建容器的文件系统。联合文件系统允许将多个文件系统挂载到同一个目录下,形成一个统一的文件系统视图。Docker 默认使用的联合文件系统是 OverlayFS。
- 容器镜像(Container Image):Docker 使用容器镜像来打包和分发应用程序及其依赖。容器镜像是一个只读的模板,包含了运行应用程序所需的文件系统、库、环境变量等。Docker 镜像采用分层存储的方式,每一层都是一个只读的文件系统,多个镜像可以共享相同的基础层,节省存储空间。
- 容器运行时(Container Runtime):Docker 使用容器运行时来创建和管理容器。常用的容器运行时包括 Docker 自带的 Docker Engine、Containerd、CRI-O 等。容器运行时负责加载容器镜像、创建容器的命名空间和控制组、启动容器进程等。
- Docker 守护进程(Docker Daemon):Docker 守护进程是 Docker 的核心组件,负责接收和处理用户的命令,管理容器的生命周期,与容器运行时进行交互,监控容器的状态等。
通过以上的技术和组件,Docker 实现了轻量级、快速启动、隔离性好的容器化环境。用户可以使用 Docker 命令和 API 来创建、启动、停止、删除容器,以及构建、推送、拉取和管理容器镜像。
9. docker的虚拟网络如何实现
Docker 的虚拟网络是通过 Docker 的网络驱动程序实现的,它提供了多种网络驱动程序来满足不同的网络需求。以下是 Docker 虚拟网络的几种常见实现方式:
- 桥接网络(Bridge Network):桥接网络是 Docker 默认的网络驱动程序。它通过创建一个虚拟的网络桥接设备(bridge),将容器连接到这个桥接设备上,从而实现容器之间的通信。每个容器都会分配一个 IP 地址,并可以通过容器名称或 IP 地址进行访问。
- 主机网络(Host Network):主机网络模式将容器直接连接到宿主机的网络栈,容器与宿主机共享同一个网络命名空间。这种模式下,容器可以使用宿主机的 IP 地址和端口,实现与外部网络的通信,但容器之间的网络隔离性较差。
- Overlay 网络(Overlay Network):Overlay 网络是一种跨主机的虚拟网络,用于连接分布在不同主机上的容器。它使用 VXLAN(Virtual Extensible LAN)技术将不同主机上的容器连接到同一个虚拟网络中,实现容器之间的通信。Overlay 网络可以通过 Docker Swarm 或第三方网络插件进行配置和管理。
- MACVLAN 网络(MACVLAN Network):MACVLAN 网络允许容器直接使用宿主机的物理网络接口卡(NIC),每个容器都可以拥有一个独立的 MAC 地址和 IP 地址。这种模式下,容器可以直接与外部网络进行通信,但需要注意网络配置的冲突和限制。
- 第三方网络插件(Third-party Network Plugins):Docker 还支持第三方网络插件,如 Calico、Weave、Flannel 等。这些插件提供了更丰富的网络功能和管理能力,例如网络策略、安全性、负载均衡等,可以根据实际需求选择合适的插件来扩展 Docker 的网络功能。
10. xss攻击
XSS(Cross-Site Scripting)攻击是一种常见的网络安全漏洞,攻击者通过注入恶意脚本代码到受信任的网页中,使得用户在浏览器中执行这些恶意脚本,从而达到攻击的目的。XSS 攻击可以分为以下几种类型:
- 存储型 XSS:攻击者将恶意脚本代码存储到目标网站的数据库中,当其他用户访问包含恶意代码的页面时,恶意代码会从服务器返回并在用户浏览器中执行。
- 反射型 XSS:攻击者将恶意脚本代码作为参数附加在 URL 中,当用户点击包含恶意代码的链接时,服务器将恶意代码返回给用户浏览器并执行。
- DOM 型 XSS:攻击者通过修改网页的 DOM 结构,使得恶意脚本代码被执行。这种攻击方式不涉及服务器的参与,而是直接在用户浏览器中执行。
XSS 攻击可能导致以下危害:
- 盗取用户敏感信息,如登录凭证、个人信息等。
- 劫持用户会话,进行恶意操作。
- 在受攻击网站上注入恶意广告或重定向到恶意网站。
- 篡改网页内容,欺骗用户或破坏网站的可信度。
为了防止 XSS 攻击,可以采取以下措施:
- 输入验证和过滤:对用户输入的数据进行验证和过滤,确保只接受合法的数据。
- 输出编码:在将用户输入的数据输出到网页时,进行适当的编码,防止恶意代码被执行。
- 使用 HTTP 头部中的 Content Security Policy(CSP)来限制页面中可执行的脚本。
- 设置 HttpOnly 属性,防止恶意脚本通过 JavaScript 访问敏感的 Cookie 数据。
- 对于存储型 XSS,对用户输入的数据进行严格的过滤和转义,确保恶意代码无法存储到数据库中。
11. sql注入
SQL注入是一种常见的网络安全漏洞,攻击者通过在应用程序的输入字段中注入恶意的SQL代码,从而绕过应用程序的输入验证,执行恶意的SQL查询或命令。这可能导致数据库被攻击者非法访问、数据泄露、数据篡改或系统瘫痪等问题。
SQL注入攻击可以分为以下几种类型:
- 基于错误的注入:攻击者通过构造恶意的SQL语句,利用应用程序返回的错误信息来获取数据库的信息。
- 基于布尔的盲注入:攻击者通过构造恶意的SQL语句,利用应用程序的不同响应来判断SQL语句的执行结果,从而逐步获取数据库的信息。
- 基于时间的盲注入:攻击者通过构造恶意的SQL语句,利用应用程序的延迟响应来判断SQL语句的执行结果,从而逐步获取数据库的信息。
15. 如何防止sql注入
要防止SQL注入攻击,可以采取以下几个关键措施:
- 输入验证和过滤:对用户输入的数据进行验证和过滤,确保只接受合法的数据。可以使用白名单或正则表达式来验证输入数据的格式和内容,并拒绝包含特殊字符或恶意代码的输入。
- 使用参数化查询或预编译语句:使用参数化查询或预编译语句可以将用户输入的数据作为参数传递给SQL查询,而不是将其直接拼接到SQL语句中。这样可以防止攻击者通过注入恶意代码来改变SQL查询的逻辑。
- 避免动态拼接SQL语句:尽量避免在应用程序中动态拼接SQL语句,特别是使用用户输入的数据拼接SQL语句。如果必须拼接SQL语句,确保对用户输入的数据进行适当的转义或编码,以防止恶意代码的注入。
- 最小权限原则:数据库用户应该具有最小的权限,只能访问必要的数据和执行必要的操作。限制数据库用户的权限可以减少攻击者的影响范围,即使发生SQL注入攻击,也能最大程度地减少损失。
- 使用安全的开发框架和库:使用经过安全审计和验证的开发框架和库,这些框架和库通常会提供内置的防御机制来防止SQL注入攻击。例如,ORM(对象关系映射)框架可以自动处理参数化查询,从而减少了手动编写SQL语句的风险。
- 日志记录和监控:记录应用程序的日志,并监控异常的SQL查询,及时发现和阻止潜在的注入攻击。定期审查日志,以便及时发现异常行为并采取相应的应对措施。
- 定期更新和维护:及时更新和维护应用程序和数据库的软件版本,以修复已知的安全漏洞。同时,定期进行安全审计和漏洞扫描,以发现和修复潜在的SQL注入漏洞。
通过综合应用上述措施,可以大大降低SQL注入攻击的风险,并保护应用程序和数据库的安全。
16. mysql的prepare
-
MySQL的PREPARE语句是一种用于执行动态SQL的机制。它允许在执行之前预先准备SQL语句,并在需要时执行该语句。PREPARE语句的语法如下:
复制PREPARE statement_name FROM 'sql_statement';
其中,statement_name
是自定义的准备语句的名称,sql_statement
是要准备的SQL语句。
使用PREPARE语句的好处是可以将SQL语句与参数分离,从而提高查询的效率和安全性。通过将参数作为占位符(如?
)放入SQL语句中,然后在执行时将具体的参数值传递给准备语句,可以避免SQL注入攻击,并且可以重复使用准备语句以提高性能。
下面是一个使用PREPARE语句的示例:
复制PREPARE stmt FROM 'SELECT * FROM users WHERE id = ?';
SET @id = 1;
EXECUTE stmt USING @id;
在上述示例中,首先使用PREPARE语句准备了一个查询语句,然后使用EXECUTE语句执行该准备语句,并通过USING子句将参数值传递给准备语句。
执行PREPARE语句后,可以使用DEALLOCATE PREPARE语句来释放准备语句的资源,例如:
复制DEALLOCATE PREPARE stmt;
通过PREPARE语句,可以动态构建和执行SQL语句,提高查询的效率和安全性。但需要注意的是,PREPARE语句在使用时需要谨慎处理参数,确保参数的合法性和正确性,以避免潜在的安全风险。
17. mysql唯一索引和主键索引区别 唯一索引可以空吗 主键索引可以空吗
唯一索引和主键索引在MySQL中有一些区别,包括是否允许为空和是否可以有重复值。
- 唯一索引(Unique Index):
- 唯一索引允许为空值,即可以在索引列中存储NULL值。
- 唯一索引可以用来保证数据表中某列的值是唯一的。
- 主键索引(Primary Key Index):
- 主键索引不允许为空值,即主键列不能为空。
- 主键索引要求每个索引值都是唯一的。
- 主键索引用于唯一标识数据表中的每一行数据,每个数据表只能有一个主键。
18. redis的pipeline
Redis的pipeline是一种在客户端与服务器之间进行批量命令传输和响应的技术。它允许客户端一次性发送多个命令给服务器,而不需要等待每个命令的响应。服务器收到这些命令后,会将它们按顺序执行,并将所有命令的响应一次性返回给客户端,从而减少了通信的往返次数,提高了性能和吞吐量。Pipeline对于需要批量处理的场景非常有用,例如批量写入、批量读取等。
19. 读接口并发量高怎么优化(限流,缓存,数据库查询优化)
读接口并发量高时,可以采取以下优化措施:
- 限流机制: 实现限流可以控制接口的访问速率,防止过多请求同时访问导致服务器压力过大。常见的限流算法包括令牌桶算法和漏桶算法。
- 缓存: 使用缓存可以减轻数据库的压力,提高读取数据的速度。将热点数据存储在缓存中,当有请求访问时,首先从缓存中获取数据,减少对数据库的频繁查询。可以使用像Redis这样的内存数据库来存储缓存数据。
- 数据库查询优化: 优化数据库查询可以减少查询时间,提高数据库的响应速度。可以通过添加索引、优化SQL语句、分库分表等方式来提升数据库的性能。确保数据库的配置和硬件资源足够支持高并发的读取请求。
- 异步处理: 将读取接口的处理逻辑进行异步化,可以提高接口的并发处理能力。使用消息队列等技术将请求放入队列中,然后异步处理队列中的请求,减少请求的排队等待时间。
- 水平扩展: 如果单台服务器无法满足高并发请求,可以考虑使用负载均衡技术将请求分发到多台服务器上,实现水平扩展,从而提高整个系统的并发处理能力。
20. 写接口并发量高怎么优化(异步+批量)
写接口并发量高时,可以采取以下优化措施:
- 异步处理: 将写接口的处理逻辑进行异步化,使用消息队列等技术将请求放入队列中,然后异步处理队列中的请求。这样可以减少请求的排队等待时间,提高接口的并发处理能力。
- 批量处理: 将多个写操作合并成批量操作,减少单个写操作的次数,从而减少对数据库的频繁访问。通过批量操作可以提高数据库的吞吐量,减少写入操作的响应时间。
分享者:Sukidal