大型网站架构演进和架构师需具备的基础能力

[架构设计] 01 大型网站架构演进

用户最初通过在浏览器地址栏输入网址来上网,打开的是静态单页网站,包含HTML、JavaScript和CSS样式。

image-20240326142713875

随着时间发展,网站进化成动态交互模式,引入了数据库,使用户能与服务器进行双向交互,如增加、删除、修改数据。

image-20240326143413170

随后出现了单体架构,用户访问服务器,而服务器内部署了应用程序、文件服务器和数据库。

image-20240326143454416

但随着流量增加,为避免服务器性能下降,将不同功能分离部署:网站数据放在应用服务器,用户上传的文件存储在文件服务器,数据库也独立部署。这种分离可以降低用户请求的延迟,提高并发能力和存储空间。

image-20240326143523416

然而,单体服务仍有瓶颈,为解决大规模用户访问问题,引入了缓存中间件,减轻数据库压力并提高用户体验。

image-20240326143606182

但单节点部署存在风险,因此进一步发展为集群负载均衡,通过部署多个相同的应用实例(集群)来分摊流量,提升整体系统性能。

image-20240326143658594

当读操作占大部分时,采用读写分离策略,设置主从数据库以优化性能。

image-20240326143725837

进一步地,当单表数据量巨大时,采用分库分表策略,将数据散列到不同数据库中,实现分布式数据库。

image-20240326143753609

海量数据检索可以引入搜索引擎技术(如 ElasticSearch)贴合用户需求,也可以保护数据库。

image-20240326143842523

最后,面对业务复杂性,采取微服务架构,将业务拆分成独立的子项目,每个子项目有自己的数据库并可独立扩展。但这增加了代码复杂性和运维难度,同时需处理分布式事务问题。

image-20240326144139535

整个演变过程根据企业业务需求灵活调整,目标是满足用户需求,保证系统稳定高效运行。

image-20240326144301774

架构师应该具备的能力和技术知识

成为Java架构师,需要驾驭大型互联网的架构与落地。主要技术包括前后端分离架构、负载均衡、微服务、数据库读写分离、缓存技术和消息队列等。

  • 前后端分离架构:用户请求首先会经过前端,然后进入后端。负载均衡器负责将请求分发到不同的服务器,以保证系统的高可用性。
  • 微服务架构:微服务是一个独立的系统,有自己的数据库,可以与其他服务进行通信。当请求量增大时,可以通过读写分离和缓存技术来减轻数据库的压力。
  • 数据库读写分离和缓存技术:为了提高效率,可以将一部分常用数据存储在缓存中,减少对数据库的访问。同时,数据库之间也可以通过读写分离来分散压力。
  • 消息队列:服务之间可以通过消息队列进行通信,也可以调用公共资源,如推送、短信和邮件等。

大型互联网系统的架构和实施过程

image-20240326151429901

  • 前端和后端交互的过程及其中涉及的关键技术

    • 当用户通过浏览器或移动设备等方式访问网站时,前端负责接收用户的请求并将它们传递给后台。
    • 为了提高可用性和可靠性,在此过程中通常会引入负载均衡器(如Nginx)将流量分配到多台服务器上。如果一台服务器出现问题,另一台备机会立即接管工作。
  • 深入解析Spring Cloud微服务体系结构及其组成部分

  • 微服务架构下,每项业务功能都被视为独立的服务单元。每个服务都有自己的数据库用于存储相关的数据信息,并支持读写分离策略以降低数据库压力。Redis缓存的作用,可以加速某些频繁使用的数据操作。

  • 分布式系统的设计原则和关键挑战

    • 分布式系统的核心概念——数据一致性和事务隔离性等问题。
    • 如何利用锁机制来解决这些问题,解决方案—分布式Session。
    • 应对高并发情况下的限流问题以及分布式日志记录的问题。
    • 其他重要的技术解决方案例如Distributed File System (DFS) 和 Elasticsearch Search Engine(ES)
    • 其中提到的Elasticsearch搜索引擎(ES)是一款开源的企业搜索平台,它可以处理大量的数据,并提供快速高效的查询结果。此外,该引擎还可以与其他工具和服务集成,如Apache Hadoop和Amazon Web Services等,从而进一步增强其性能和实用性。

Views: 41

RHEL 9 新特性及技术演示

image-20240325023617906

预览

  • RHEL 9 新特性与演示:

  • OpenSSH:新增禁止 root 的密码登录

  • Cockpit:RHEL 的 Web 控制台

  • DNF-3:软件安装方法

  • NetworkManager:网络管理的主要组件

  • Nftables:默认的用户空间防火墙

  • WireGuard:快速、安全的 VPN 隧道(技术预览

  • Podman & Skopeo:新一代容器运行时与镜像搬运工具

  • LVM-VDO:以逻辑卷形式使用 VDO

RHEL 9 新特性与演示 - OpenSSH

  • RHEL 9.0 中的 OpenSSH 套件版本:

    • openssh-8.7p1-8.el9.x86_64

    • openssh-clients-8.7p1-8.el9.x86_64

    • openssh-server-8.7p1-8.el9.x86_64

  • OpenSSH server:

    • 默认禁止 root 的密码登录

    • PermitRootLogin prohibit-password

image-20240325023639104

RHEL 9 新特性与演示 - Cockpit

  • Cockpit:RHEL 的 Web 控制台

  • Cockpit 自 RHEL 8 开始加入系统中作为 Web 图形化控制台,可帮助系统管理员快速查看系统状态,并对系统实施简易的运维工作。

  • RHEL 9 中的 Cockpit 增强:

    • 单个 Web 控制台中添加多个主机
    • KVM 虚拟机的管理:cockpit-machines 插件
    • 原生容器镜像与容器的管理:cockpit-podman 插件
    • PCP (Performance Co-Pilot) 的支持:cockpit-pcp 插件
  • 启动 cockpit 服务并设置开机自启动

$ sudo systemctl enable --now cockpit.socket
$ sudo systemctl start cockpit.service
$ sudo systemctl status cockpit.service
$ sudo ss -ntulp | grep 9090

image-20240325023721085

image-20240325023847847

$ sudo systemctl enable --now serial-getty@ttyS0.service:

虚拟机中启用串口控制台连接服务

RHEL 9 新特性与演示 - DNF-3

  • 自 RHEL 8 开始使用 dnf-3 用于安装 RPM 软件包。

  • RHEL 8 与 RHEL 9 中原有的 yum 安装工具依然可继续使用,yum 为 dnf-3 的软链接。

RHEL 9 的软件源管理:

  • 采用 BaseOS 与 AppStream 软件仓库分开管理

  • 支持模块流(module stream)可同时安装相同软件的不同版本

image-20240325024004211

RHEL 9 新特性与演示- NetworkManager

  • RHEL 7 中可使用 network.service 与 NetworkManager.service 两个服务用于网络管理。

  • RHEL 8 中默认使用 NetworkManager.service,而不再默认安装 network.service (network-scripts 软件包提供),但是可手动安装该组件。

  • 可通过 nmcli 命令行或 /etc/sysconfig/network-scripts/ifcfg-* 配置文件进行配置。

image-20240325024049070

  • RHEL 9 中不再提供 network-scripts 软件包,只能使用 NetworkManager.service。

  • RHEL 9 网络配置工具:

    • 命令行:nmcli

    • 图形化:nm-connection-editor、nmtui、nmtui-connect、nmtui-edit

  • RHEL 8 中兼容的 ifdown 与 ifup 命令在 RHEL 9 中已弃用。

  • RHEL 9 网口配置文件路径:

    • /etc/NetworkManager/system-connections/*.nmconnection

    • /etc/sysconfig/network-scripts/ifcfg-* 配置文件依然可用,但是建议使用上述配置文件!

image-20240325024122613

RHEL 9 新特性与演示 - NetworkManager

  • RHEL 8 与 RHEL 9 网口配置对比:

image-20240325024150855

image-20240325024349025

image-20240325024424400

RHEL 9 新特性与演示 - Nftables

  • RHEL 7 中使用 firewalld 服务作为用户配置防火墙规则的工具,iptables 作为实现防火墙规则的用户空间实现,因此通过 firewall-cmd 与 iptables 命令行均可实现防火墙的配置。

  • RHEL 8 中也使用 firewalld 服务,但其后端默认通过 nftables 实现防火墙规则,iptables 也可作为其后端,但为非默认配置可通过手动生效。

image-20240325024516788

  • firewalld、iptables 与 nftables 之间的联系与区别:

image-20240325024545693

image-20240325024605921

  • nftables 和 iptables 一样,由表(table)、链(chain)和规则(rule)组成,其中表包含链,链包含规则,规则是真正的 action。

  • 与 iptables 相比,nftables 主要有以下几个变化:

    • iptables 规则的布局是基于连续的大块内存的,即数组式布局;而 nftables 的规则采用链式布局(数组和链表的区别)。

    • iptables 大部分工作在内核态完成,如果要添加新功能,只能重新编译内核;而 nftables 的大部分工作是在用户态完成,添加新功能不需要改内核。

  • iptables 有内置的链,即使只需要一条链,其他的链也会跟着注册;而 nftables 不存在内置的链,可以按需注册。

  • 由于 iptables 内置了一个数据包计数器,所以即使这些内置的链是空的,也会带来性能损耗。

  • 简化了 IPv4/IPv6 双栈管理

  • 原生支持集合(IPset)、字典和映射

  • 示例:nftables 添加 SNAT 规则使 KVM 虚拟机访问外网

  • KVM 虚拟机与宿主机的网络状态:

image-20240325024702459

  • KVM 宿主机的 nft 命令示意:
$ sudo systemctl stop firewalld.service
$ sudo nft list ruleset
  • nftables 不存在内置链,关闭 firewalld 服务后,原先由 firewalld 创建的规则也将置空。
$ sudo nft add rule nat POSTROUTING ip saddr 172.25.10.0/24 oif bridge0 snat 192.168.110.200
  • 添加 nftables 的 SNAT 规则

$ sudo nft list table ip nat

  • 查看 nftables 的 NAT 表规则

image-20240325024741173

  • 若发现在 nftables 中无任何表,需从头创建 nat 表、POSTROUTING 基本链与 SNAT 规则,如下所示:

image-20240325024813953

RHEL 9 新特性与演示 - WireGuard

image-20240325024849706

RHEL 9 中 Linux kernel 为 5.14.0,kernel 已支持 WireGuard 功能,但还处于技术预览阶段,不推荐在生产环境中使用。

WireGuard 是由 Jason Donenfeld 等人用 C 语言编写的一个开源 VPN 协议,被视为下一代 VPN 协议,旨在解决许多困扰 IPSec/IKEv2、OpenVPN 或 L2TP 等其他 VPN 协议的问题。它与 Tinc 和 MeshBird 等现代 VPN 产品有一些相似之处,即加密技术先进、配置简单。从 2020 年 1 月开始,它已经并入了 Linux 内核的 5.6 版本,这意味着大多数 Linux 发行版的用户将拥有一个开箱即用的 WireGuard。

  • WireGuard 与其他 VPN 协议的性能测试对比:

image-20240325024906182

  • WireGuard 优点:

    • 配置精简,可直接使用默认值。

    • 只需最少的密钥管理工作,每个主机只需要 1 个公钥和 1 个私钥。

    • 就像普通的以太网接口一样,以 Linux 内核模块的形式运行,资源占用小。

    • 能够将部分流量或所有流量通过 VPN 传送到局域网内的任意主机。

    • 能够在网络故障恢复之后自动重连,戳到了其他 VPN 的痛处。

    • 比目前主流的 VPN 协议,连接速度要更快,延迟更低(见上图)。

    • 使用了更先进的加密技术,具有前向加密和抗降级攻击的能力。

    • 支持任何类型的二层网络通信,例如 ARP、DHCP 和 ICMP,而不仅仅是 TCP/HTTP。

    • 可以运行在主机中为容器之间提供通信,也可以运行在容器中为主机之间提供通信。

  • WireGuard 功能示例:

    • 由于 RHEL 9 中 kernel 已支持 WireGuard,因此只需安装 wireguard-tools 软件包即可。

    • 创建 client 端与 server 端的 vpn 通信。

Ubuntu 20.04.3 LTS:

WireGuard Server(Peer) 192.0.2.1/24, 192.168.110.208/24

image-20240325024941693

  • RHEL 9.0 Beta:

    • WireGuard Client(Peer) 192.0.2.2/24, 172.25.10.11/24, gateway: 192.168.110.1

image-20240325025014423

image-20240325025035557

RHEL 9 新特性与演示 - Podman & Skopeo

  • Podman 作为下一代容器运行时自 RHEL 8 开始正式在 RHEL 中替代 Docker,红帽官方不再使用 Docker,并且还提供两个强大的容器镜像操作工具 Skopeo 与 Buildah。

  • Podman 在 RHEL 9 中版本为 4.0.x,其功能得到增强且更加稳定。

  • Podman 4.0.x 在兼容 CNI 的基础上又新增原生的网络模式 Netavark 与 Aardvark-DNS 以更好的支持 IPv6、单容器接入多个容器网络与提供更好的性能。

  • Podman 的以下特性:

    • CLI 与 Docker 命令行相互兼容,可平滑过度。

    • 同样支持 Dockerfile 构建容器镜像,并且兼容 Containerfile。

    • 无守护进程运行,采用 fork/exec 模型运行容器。

    • 可运行 rootfull 与 rootless 容器

    • 可以实现容器随操作系统启动而启动

  • 虽然 Podman 可执行部分容器镜像相关操作,但在执行效率上与 Skopeo 相比相差甚远,因此,若对容器镜像执行操作可使用 Skopeo 与 Buildah 替换。

  • 有关 Podman 与 Skopeo 的详细内容可参阅最后的 Alberthua Blog 参考链接。

  • Podman & Skopeo 命令示例:

image-20240325025154265

image-20240325025220569

image-20240325025239938

  • Podman 各特征比较:

image-20240325025254980

RHEL 9 新特性与演示 - LVM-VDO

  • RHEL 9 在存储方面增加了较多特性,如已支持 exfat 文件系统、LVM-VDO 卷存储等。

  • 单纯使用 VDO 卷功能已从 RHEL 9 中移除。

  • 注:RHEL 9.0 Beta 中 kmod-kvdo 内核模块当前仍存在 bug,该模块所需的内核版本与系统当前版本无法匹配。

image-20240325025315776

参考链接

Views: 25

Linux 的 loginctl 命令详解

在使用podman创建无根用户服务时, 除了通过systemctl enable ...设置开机自启, 还需要在当前用户执行 loginctl enable-linger`, 那么这个命令到底是做什么的呢?

loginctl 并不是一个常用 Linux 命令,大部分时候都用不到它。这个命令隶属于 Systemd 的一部分,是 systemd 的登录管理器。

loginctl 命令格式

loginctl [选项...] {命令} [用户名...]

loginctl 命令示例

列出登录的用户:

loginctl list-users

列出登录的用户和会话:

loginctl list-sessions

列出当前用户的登录信息:

loginctl show-user $USER

Systemd 支持通过 --user 参数管理用户级别的后台程序,不过这存在一个问题,如果用户退出登录后,属于该用户的后台服务会被终止。如果希望用户退出后仍然保持服务的运行,可以使用下面的命令启用用户的逗留状态:

loginctl enable-linger $USER

loginctl 命令选项

缩写 完整名称 说明
--no-ask-password 在执行特权操作时不向用户索要密码。
-p --property= 在显示 session/user/seat 属性时, 仅显示此处指定的属性。 若未指定,则显示全部属性。 参数必须是属性名(例如"Sessions")。 可以多次使用此选项以指定多个属性。
--value 在使用 show 显示属性时, 仅显示属性值,而不显示属性名及等号。
-a --all 在显示 session/user/seat 属性时, 显示全部属性,无论这些属性是否已经被设置。
-l --full 在显示进程树的时候,不对超长行进行截断。
--kill-who= 与 kill-session 连用,指定杀死哪个进程。 leader 表示仅杀死会话的领导进程; all 表示杀死会话的所有进程。 默认值为 all
-s --signal= 与 kill-session 或 kill-user 连用, 指定向选中的进程发送什么信号。 必须设为众所周知的信号名称,例如 SIGTERM(默认值), SIGINT, SIGSTOP 之类
-n --lines= 与 user-status 或 session-status 连用, 控制显示多少行日志(从最新的一条日志开始计算)。 必须设为一个正整数,默认值是"10"。
-o --output= 与 user-status 或 session-status 连用, 控制日志的输出格式。 可用值参见 journalctl(1) 手册。默认为 "short"
-H --host= 操作指定的远程主机。可以仅指定一个主机名(hostname), 也可以使用 "username@hostname" 格式。 hostname 后面还可以加上容器名(以冒号分隔), 也就是形如 "hostname:container" 的格式, 以表示直接连接到指定主机的指定容器内。 操作将通过 SSH 协议进行,以确保安全。 可以通过 machinectl -H HOST 命令列出远程主机上的所有容器名称。
-M --machine= 在本地容器内执行操作。 必须明确指定容器的名称。
--no-pager 不将程序的输出内容管道(pipe)给分页程序。
--no-legend 不输出列标题, 也就是不在输出列表的头部和尾部显示字段的名称。
-h --help 显示简短的帮助信息并退出。
--version 显示简短的版本信息并退出。

loginctl 参数命令

loginctl 有三种参数命令,分别是:会话命令,用户命令和席位命令。

会话命令

名称 说明
list-sessions 列出当前所有的会话。这是默认命令。
session-status [ID...] 显示简洁的会话状态信息,后跟最近的日志。 如果指定了会话ID,那么仅显示指定的会话, 否则显示当前调用者的会话。 此命令主要用于输出人类易读的信息, 如果你想输出易于程序分析的信息, 那么应该使用 show-session 命令
show-session [ID...] 如果指定了会话ID,那么显示指定会话的各项属性值, 否则显示登陆管理器自身的各项属性值。 除非使用了 --all 选项, 否则空属性将被忽略。 还可以使用 --property= 选项指定仅显示个别属性。 此命令主要用于输出易于程序分析的信息, 如果你想输出人类易读的信息, 那么应该使用 session-status 命令。
activate [ID] 激活会话。 也就是将处于后台的会话切换到前台(如果同席位的另一个会话正处于前台)。 如果指定了会话ID, 那么将激活指定的会话, 否则将激活当前调用者的会话。
lock-session [ID...], unlock-session [ID...] 锁定/解锁会话(如果会话支持屏幕锁)。 如果指定了会话ID,那么将锁定/解锁指定的会话, 否则将锁定/解锁当前调用者的会话。
lock-sessionsunlock-sessions 锁定/解锁所有支持屏幕锁的会话。
terminate-session ID... 结束指定的会话。 也就是杀死指定会话的所有进程、释放所有与此会话相关的资源。
kill-session ID... 向指定的会话进程发送信号。 使用 --kill-who= 指定目标进程, 使用 --signal= 指定要发送的信号。

用户命令

名称 说明
list-users 列出当前登录的用户。
user-status [USER...] 显示简洁的已登录用户信息,后跟最近的日志。 如果指定了用户名或UID, 那么仅显示指定的用户, 否则显示当前调用者的用户。 此命令主要用于输出人类易读的信息, 如果你想输出易于程序分析的信息, 那么应该使用 show-user 命令。
show-user [USER...] 如果指定了用户名或UID,那么显示指定用户的各项属性值, 否则显示登陆管理器自身的各项属性值。 除非使用了 --all 选项, 否则空属性将被忽略。 还可以使用 --property= 选项来显示指定的属性。此命令主要用于输出易于程序分析的信息, 如果你想输出人类易读的信息, 那么应该使用 user-status 命令。
enable-linger [USER...], disable-linger [USER...] 启用/禁止用户逗留(相当于保持登录状态)。 如果指定了用户名或UID, 那么系统将会在启动时自动为这些用户派生出用户管理器, 并且在用户登出后继续保持运行。 这样就可以允许未登录的用户在后台运行持续时间很长的服务。 如果没有指定任何参数, 那么将作用于当前调用者的用户。
terminate-user USER... 结束指定用户的所有会话。 这将杀死该用户的所有会话中的所有进程, 同时释放与此用户有关的所有资源。
kill-user USER... 向指定用户的所有进程发送 --signal= 选项指定的信号。

席位命令

名称 说明
list-seats 列出当前本机上的所有可用席位
seat-status [NAME...] 显示简洁的席位信息,后跟最近的日志。 如果指定了席位名,那么仅显示指定的席位, 否则显示当前调用者会话所属的席位。 此命令主要用于输出人类易读的信息, 如果你想输出易于程序分析的信息, 那么应该使用 show-seat 命令。
show-seat [NAME...] 如果指定了席位名,那么显示指定席位的各项属性值, 否则显示登陆管理器自身的各项属性值。 除非使用了 --all 选项, 否则空属性将被忽略。 还可以使用 --property= 选项来显示指定的属性。 此命令主要用于输出易于程序分析的信息, 如果你想输出人类易读的信息, 那么应该使用 seat-status 命令。
attach NAME DEVICE... 将指定的设备(DEVICE)持久的连接到指定的席位(NAME)上。 设备可以用相对于 /sys 文件系统的设备路径表示。 要创建一个新席位,至少需要连接一个显卡。 席位名称必须以 "seat" 开头, 后跟 a–z, A–Z, 0–9, "-", "_" 字符。 要想从席位上删除一个设备, 可以将此设备连接到另一个席位, 或者使用 flush-devices 命令。
flush-devices 删除所有先前用 attach 命令连接的设备(同时也删除了所有先前用 attach 命令创建的席位)。 调用此命令之后,所有自动生成的席位将会被保留, 同时所有席位设备将会连接到自动生成的席位上。
terminate-seat NAME... 结束指定席位上的所有会话。 这将杀死指定席位上的所有会话进程, 同时释放与之关联的所有资源。

Views: 6

nginx配置中location匹配规则和优先级

location 介绍

location是Nginx中的块级指令(block directive),location指令的功能是用来匹配不同的url请求,进而对请求做不同的处理和响应,这其中较难理解的是多个location的匹配顺序,本文会作为重点来解释和说明。

开始之前先明确一些约定,我们输入的网址叫做请求URI,nginx用请求URI与location中配置的URI做匹配。

localtion 语法

location有两种匹配规则:

匹配URL类型,有四种参数可选,当然也可以不带参数。

location [ = | ~ | ~* | ^~ ] uri { … }

命名location,用@标识,类似于定于goto语句块。

location @name { … }

location匹配参数解释:

“=” ,精确匹配

内容要同表达式完全一致才匹配成功

location = /abc/ {
  .....
 }

# 只匹配http://abc.com/abc
#http://abc.com/abc [匹配成功]
#http://abc.com/abc/index [匹配失败]

“~”,执行正则匹配,区分大小写。

location ~ /Abc/ {
  .....
}
#http://abc.com/Abc/ [匹配成功]
#http://abc.com/abc/ [匹配失败]

“~*”,执行正则匹配,忽略大小写

location ~* /Abc/ {
  .....
}
# 则会忽略 uri 部分的大小写
#http://abc.com/Abc/ [匹配成功]
#http://abc.com/abc/ [匹配成功]

“^~”,表示普通字符串匹配上以后不再进行正则匹配。

location ^~ /index/ {
  .....
}
#以 /index/ 开头的请求,都会匹配上
#http://abc.com/index/index.page  [匹配成功]
#http://abc.com/error/error.page [匹配失败]

不加任何规则

不加任何规则时,默认是大小写敏感,前缀匹配,相当于加了“~”与“^~”

location /index/ {
  ......
}
#http://abc.com/index  [匹配成功]
#http://abc.com/index/index.page  [匹配成功]
#http://abc.com/test/index  [匹配失败]
#http://abc.com/Index  [匹配失败]

“@”,nginx内部跳转

location /index/ {
  error_page 404 @index_error;
}
location @index_error {
  .....
}

以 /index/ 开头的请求,如果链接的状态为 404。则会匹配到 @index_error 这条规则上。

location匹配顺序

= > ^~ > ~ | ~* > 最长前缀匹配 > /

序号越小优先级越高

location = # 精准匹配

location ^~ # 带参前缀匹配

location ~ # 正则匹配(区分大小写)

location ~* # 正则匹配(不区分大小写)

location /a # 普通前缀匹配,优先级低于带参数前缀匹配。

location / # 任何没有匹配成功的,都会匹配这里处理

举例

location = /  {
#规则A
}

location = /login {
#规则B
}

location ^~ /static/ {
#规则C
}

location ~ \.(gif|jpg|png|js|css)$ {
#规则D
}

location ~* \.png$ {
#规则E
}

location !~ \.xhtml$ {
#规则F
}

location !~* \.xhtml$ {
#规则G
}

location / {
#规则H
}

匹配结果:

访问根目录/, 比如http://localhost/ 将匹配规则A

访问 http://localhost/login 将匹配规则B,http://localhost/register 则匹配规则H

访问 http://localhost/static/a.html 将匹配规则C

访问 http://localhost/b.jpg 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用, 而 http://localhost/static/c.png 则优先匹配到 规则C

访问 http://localhost/a.PNG 则匹配规则E, 而不会匹配规则D,因为规则E不区分大小写。

访问 http://localhost/a.xhtml 不会匹配规则F和规则G,http://localhost/a.XHTML 不会匹配规则G,因为不区分大小写。规则F,规则G属于排除法,符合匹配规则但是不会匹配到。

访问 http://localhost/qll/id/1111 则最终匹配到规则H,因为以上规则都不匹配。

location URI结尾带不带 /

如果 URI 结构是 https://domain.com/ 的形式,尾部有没有 / 都不会造成重定向。因为浏览器在发起请求的时候,默认加上了 / 。虽然很多浏览器在地址栏里也不会显示 / 。这一点,可以访问百度验证一下。

使用curl命令访问的时候是不会默认加上/

如果 URI 的结构是 https://domain.com/some-dir/ 。尾部如果缺少 / 将导致重定向。因为约定,URL 尾部的 / 表示目录,没有 / 表示文件。所以访问 /some-dir/ 时,服务器会自动去该目录下找对应的默认文件。如果访问 /some-dir 的话,服务器会先去找 some-dir 文件,找不到的话会将 some-dir 当成目录,重定向到 /some-dir/ ,去该目录下找默认文件。

举个例子:

server {
    listen       9001;
    server_name  www.abc.com;

    location ~ /edu {
        proxy_pass http://127.0.0.1:8080;
     }
  }

我们访问www.abc.com:9001/edu,看下效果

访问 /edu 时,服务器首先去找edu文件,找不到则将edu当做目录,重定向到 /edu/,在该目录下找默认文件。

但是如果想这两种请求对应不同的处理,就要明确增加不带/结尾的location配置。例如:

location  /doc {
  proxy_pass http://www.doc123.com
}
location  /doc/ {
  proxy_pass http://www.doc456.com
}

Views: 5

docker容器环境使用pgloader迁移MySQL数据库到PostgreSql

情况描述

目前我的mysql和postgresql都安装在本地, 并且没有开放外部访问权限.
为了节省服务器资源需要把mysql的db数据库数据迁移至postgre.
服务器是CentOS7, docker环境已经安装

拉取镜像

docker pull dimitri/pgloader

创建容器

pgloader 没找到合适的yum源, 用源码安装中途卡住, 所以考虑使用docker安装

使用 host 网络模式, 表示容器在本机网络中运行, localhost表示宿主机.

docker run -itd --network host --name pgloader_container dimitri/pgloader

编写配置

vim pgloader.load

编辑如下:

LOAD DATABASE
 FROM mysql://root:xxxx@localhost:3306/db
 INTO pgsql://postgres:xxxx@localhost:5432/db
WITH include drop, create tables,disable triggers, create indexes,foreign keys, reset no sequences, workers = 8, concurrency = 1, multiple readers per thread, rows per range = 50000
CAST  type timestamp to timestamp drop default drop not null using zero-dates-to-null
ALTER SCHEMA 'db' RENAME TO 'public';

默认会使用mysql的数据库名称作为pgsql的schema名称, 这里改成默认的public

运行容器

拷贝配置到容器根目录

docker cp pgload.load pgloader_container:/

进入容器, 执行导入, 等待数据转移完成.退出容器:

docker exec -it pgloader_container /bin/bash
pgloader pgloader.load
... ...
exit

如果不再需要, 清除容器和镜像.

docker kill pgloader_container
docker rm pgloader_container
docker image rm  dimitri/pgloader

Views: 6