第十九周作业

1、haproxy https实现

  1. 配置haproxy,执行SSL加解密
[root@centos8mini ~]# cat /etc/haproxy/haproxy.cfg
...
frontend www
    log global
    option httplog
    bind 192.168.156.11:80
    #需要加上ssl选项
    bind 192.168.156.11:443 ssl crt /root/mxx.pem 
    #http到https重定向
    redirect scheme https if ! { ssl_fc }
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }
    use_backend aaa
    mode http 
    #capture request header Host len  256
    #capture request header User-Agent len 512
    #capture request header Referer len 15
    #capture request header X-Forwarded-For len 15

backend aaa
    cookie Dserver insert nocache indirect
    server rs1 192.168.156.202:80 cookie web1 send-proxy
    server rs2 192.168.156.204:80 cookie web2 send-proxy
...
  1. 配置nginx日志,记录x-forwarded-port和x-forwarded-proto信息:
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$host" "$proxy_protocol_addr" "$http_x_forwarded_port" "$http_x_forwarded_proto"';  
  1. 测试结果
#后端服务器可以看到https,haproxy加上去的请求头部字段
192.168.156.208 - - [21/Jan/2022:21:11:36 +0800] "GET / HTTP/1.1" 200 110 "-" "curl/7.58.0" "192.168.156.100" "www.mxx.com" "192.168.156.100" "443" "https"
  1. 抓包可以看到前端是80切443,后端一直是80,ssl的加解密由haproxy完成
#客户端100去访问VIP 156.11的443端口
21:24:23.882974 IP 192.168.156.11.443 > 192.168.156.100.37330: Flags [P.], seq 1353:1624, ack 695, win 235, options [nop,nop,TS val 3578864071 ecr 3498970570], length 271
21:24:23.883118 IP 192.168.156.11.443 > 192.168.156.100.37330: Flags [P.], seq 1624:1895, ack 695, win 235, options [nop,nop,TS val 3578864071 ecr 3498970570], length 271
21:24:23.883393 IP 192.168.156.100.37330 > 192.168.156.11.443: Flags [.], ack 1895, win 501, options [nop,nop,TS val 3498970571 ecr 3578864071], length 0

#haproxy 208去访问后端的204的80端口
21:24:23.883424 IP 192.168.156.208.46246 > 192.168.156.204.80: Flags [S], seq 3363885263, win 29200, options [mss 1460,sackOK,TS val 3269997331 ecr 0,nop,wscale 7], length 0
21:24:23.883460 IP 192.168.156.204.80 > 192.168.156.208.46246: Flags [S.], seq 3613891712, ack 3363885264, win 28960, options [mss 1460,sackOK,TS val 1974460156 ecr 3269997331,nop,wscale 7], length 0
21:24:23.884099 IP 192.168.156.208.46246 > 192.168.156.204.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 3269997332 ecr 1974460156], length 0
21:24:23.884167 IP 192.168.156.208.46246 > 192.168.156.204.80: Flags [P.], seq 1:231, ack 1, win 229, options [nop,nop,TS val 3269997332 ecr 1974460156], length 230: HTTP
21:24:23.884177 IP 192.168.156.204.80 > 192.168.156.208.46246: Flags [.], ack 231, win 235, options [nop,nop,TS val 1974460157 ecr 3269997332], length 0

2、总结tomcat的核心组件以及根目录结构

tomcat核心组件

  • Server组件:一个server就是一个tomcat实例,不同server使用不同的端口
  • service组件:包含了Engine和Connector的对应关系
  • Connector组件:可以简单理解为一个监听端口,包含HTTP、HTTPS、AJP协议的连接器
  • 容器类组件:在Engine内创建多个Host,Host内可以配置本地磁盘路径和URL路径的关联关系
    • Engine:接收用户通过某个接口发送的处理请求;Server里只有一个Engine
    • Host:一个Engine可以包含多个虚拟主机,和Apache、Nginx的虚拟主机是一样的概念,通过端口、IP、域名等方式区分虚拟主机
    • Context:执行路径映射,类似Apache或Nginx里的Location,配置磁盘目录和URL路径的关联关系
  • 内嵌类:可以内嵌到其他组件内,如valve、logger、realm、loader、manager等
  • 集群类组件:listener、cluster

根目录结构

  • bin/:包含服务启动、停止的程序和文件,如shutdown.sh、startup.sh、catalina.sh等
  • conf/:包含全局配置文件,比如启动service时,EnvironmentFile=tomcat.conf文件、web.xml、server.xml、context.xml、tomcat-users.xml等
  • lib/:java库目录
  • logs/:日志文件的存放位置
  • webapps/:类似apache的/var/www/html,是tomcat默认页面的存放路径
  • work/:jsp编译后的字节码和servlet文件存放位置,通常jsp文件需要被提前预热访问,以加快用户的访问速度;
    • 该目录中的缓存文件可能会影响新版本资源的发布,需要删除这些自动生成的文件,让新版本的jsp可以重新生成

3、tomcat实现多虚拟主机

#!/bin/bash
#****************************************************************************************#
#Author:                        Yabao11
#QQ:                            what QQ,no QQ
#Date:                          2022-01-04
#FileName:                      nginx.sh
#URL:                           https://github.com/yabao11
#Description:                   Test Script
#Copyright (C):                 2022 All rights reserved
#*******************************定义颜色*************************************************#
RED="\e[1;31m"
GREEN="\e[1;32m"
SKYBLUE="\e[1;36m"
YELLOW="\e[1;43m"
BLUE="\e[1;44m"
END="\e[0m"
RandomColor="\e[1;32m"
#****************************************************************************************#
function Ostype {
    if grep -i -q "release 6" /etc/centos-release;then
      echo Centos6
    elif grep -i -q Centos-8 /etc/os-release;then
      echo Centos
    elif grep -i -q Centos-7 /etc/os-release;then
      echo Centos7
    elif grep -i -q Ubuntu /etc/os-release;then
      echo Ubuntu
    elif grep -i -q "RedHat" /etc/os-release;then
      echo Redhat
    fi
}

function color {
  RES_COL=60
  MOVE_TO_COL="echo -en \E[${RES_COL}G"
  SETCOLOR_SUCCESS="echo -en \E[1;32m"
  SETCOLOR_FAILURE="echo -en \E[1;31m"
  SETCOLOR_WARNING="echo -en \E[1;33m"
  SETCOLOR_NORMAL="echo -en \E[0m"
  echo -n "$1" && $MOVE_TO_COL
  echo -n "["
  if [[ $2 = "success" || $2 = "0" ]]; then
    ${SETCOLOR_SUCCESS}
    echo -n "  OK  "
  elif [[ $2 = "failure" || $2 = "1" ]]; then
    ${SETCOLOR_FAILURE}
    echo -n "FAILED"
  else
    ${SETCOLOR_WARNING}
    echo -n "WARNING"
  fi
  ${SETCOLOR_NORMAL}
  echo -n "]"
  echo
}


function jdk_install {
    read -p "输入希望二进制安装的jdk版本,直接回车默认安装'/root/jdk-8u321-linux-x64'" jdk
    oracle_jdk=${jdk:-jdk-8u321-linux-x64}

    [ -e /root/${oracle_jdk}.tar.gz ] && tar xvf /root/${oracle_jdk}.tar.gz -C /usr/local/src/ || { color "文件不存在" 2;exit; }
    mv /usr/local/src/jdk* /usr/local/src/jdk
    cat > /etc/profile.d/jdk.sh <<\EOF
export JAVA_HOME=/usr/local/src/jdk
export PATH=$PATH:$JAVA_HOME/bin
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=$JAVA_HOME/lib/:$JRE_HOME/lib/
EOF
    . /etc/profile.d/jdk.sh
    java -version > /dev/null && color "jdk安装成功!" 0
}


read -p "输入希望二进制安装的tomcat版本,直接回车默认安装'apache-tomcat-8.5.75'" tomcat
read -p "输入JAVA_HOME路径,直接回车使用默认路径:'/usr/local/src/jdk'" pjdk
read -p "输入tomcat路径,直接回车使用默认路径:'/usr/local/src/tomcat'" ptomcat
tomcat_version=${tomcat:-apache-tomcat-8.5.75}
java_path=${pjdk:-/usr/local/src/jdk}
tomcat_path=${ptomcat:-/usr/local/src/tomcat}

function tomcat_install {
    java -version > /dev/null || { color "缺少java环境!" 1;exit; }
    [ -e /root/${tomcat_version}.tar.gz ] || { yum -y install wget;wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.75/bin/${tomcat_version}.tar.gz; }
    [ -e /root/${tomcat_version}.tar.gz ] || { color "找不到tomcat文件" 1;exit; } 
    tar xf ${tomcat_version}.tar.gz -C /usr/local/src/
    [ -e ${tomcat_path} ] && rm -rf ${tomcat_path}
    ln -s /usr/local/src/${tomcat_version} ${tomcat_path}
    echo 'PATH=${tomcat_path}/bin:$PATH' > /etc/profile.d/tomcat.sh
    . /etc/profile.d/tomcat.sh
    useradd -r -s /sbin/nologin tomcat
    chmod +x ${tomcat_path}/bin/*
    catalina.sh version > /dev/null && color "安装成功!" 0 || color "catalina命令执行失败,请检查权限或路径" 1
    cat > ${tomcat_path}/conf/tomcat.conf <<EOF
JAVA_HOME=${java_path}
CATALINA_HOME=${tomcat_path}
EOF
    chown -R tomcat.tomcat ${tomcat_path}/ && color "tomcat目录权限修改成功" 0 || color "tomcat目录权限修改失败" 1
    echo -e $GREEN"创建tomcat.service文件"$END
    [ -e /lib/systemd/system/tomcat.service ] || cat > /lib/systemd/system/tomcat.service <<EOF
[Unit]
Description=Tomcat
#After=syslog.target network.target remote-fs.target nss-lookup.target
After=syslog.target network.target 

[Service]
Type=forking
EnvironmentFile=${tomcat_path}/conf/tomcat.conf
ExecStart=${tomcat_path}/bin/startup.sh
ExecStop=${tomcat_path}/bin/shutdown.sh
PrivateTmp=true
User=tomcat
Group=tomcat

[Install]
WantedBy=multi-user.target
EOF
    systemctl daemon-reload
    systemctl enable --now tomcat && color "tomcat启动成功!" 0 || color "tomcat启动失败,请执行journalctl -u tomcat查看日志详情" 1
}

function tomcat_config {
    sed -i.bak -r -e 's|(pattern.*)("[[:space:]]+\/>)|\1 %{JSESSIONID}c %{HOST}i %{X-Forwarded-For}i %{X-Via}o\2|' \
    -e 's|shutdown="SHUTDOWN"|shutdown="44ba3c71d57f494992641b258b965f28"|' \
    -e '/<\/Engine>/i      <Host name="www.mxx.com"  appBase="mxx"\n            unpackWARs="true" autoDeploy="true">\n        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"\n               prefix="mxx_access_log" suffix=".txt"\n               pattern="%h %l %u %t &quot;%r&quot; %s %b %{JSESSIONID}c %{HOST}i %{X-Forwarded-For}i %{X-Via}o" />\n      </Host>\n' \
    ${tomcat_path}/conf/server.xml && color "配置日志格式,修改server参数" 0
    sed -i.bak -r '/<\/tomcat-users>/i<role rolename="manager-gui"/>\n<role rolename="admin-gui"/>\n<user username="tomcat" password="tomcat" roles="manager-gui,admin-gui"/>\n' ${tomcat_path}/conf/tomcat-users.xml && color "配置允许访问tomcat的status等管理页面" 0
    sed -i.bak -r 's|(allow.*)("[[:space:]]+\/>)|\1\|\\d+\\.\\d+\\.\\d+\\.\\d+\2|' ${tomcat_path}/webapps/manager/META-INF/context.xml && color "配置允许所有IP地址访问status(测试环境)" 0
    sed -i.bak -r 's|(allow.*)("[[:space:]]+\/>)|\1\|\\d+\\.\\d+\\.\\d+\\.\\d+\2|' ${tomcat_path}/webapps/host-manager/META-INF/context.xml && color "配置允许所有IP地址访问host-manager(测试环境)" 0
    echo -e $GREEN"创建mxx虚拟主机"$END
    mkdir ${tomcat_path}/mxx/ROOT -p
    chown tomcat.tomcat ${tomcat_path}/mxx -R
    cat > ${tomcat_path}/mxx/ROOT/index.jsp <<\EOF
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" http-equiv=Content-Type content="text/html;charset=utf-8">
    <title>tomcat test</title>
</head>
<body>
<h1> Tomcat Website </h1>
<div>On  <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>

<h1>这是一个测试页面</h1>
</body>
</html>
EOF


    echo -e $GREEN"创建多个虚拟主机"$END
    while true;do
    read -p "是否需要继续创建虚拟主机?(yes or no)" askuser1
    askuser1=`echo $askuser1 | tr 'A-Z' 'a-z'`
    case $askuser1 in
        y|yes)
            let i=++i
        ;;
        n|no)
            break
        ;;
        *)
            inputerror
        ;;
    esac
    read -p "输入虚拟主机的域名" vhost
    if [ -z ${vhost} ];then
        while [ -z ${vhost} ];do
            read -p "请输入虚拟主机的域名" vhost
        done
    fi
    sed -i.bak -r -e '/<\/Engine>/i      <Host name="'${vhost}'"  appBase="mxx'$i'"\n            unpackWARs="true" autoDeploy="true">\n        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"\n               prefix="mxx'$i'_access_log" suffix=".txt"\n               pattern="%h %l %u %t &quot;%r&quot; %s %b %{JSESSIONID}c %{HOST}i %{X-Forwarded-For}i %{X-Via}o" />\n      </Host>\n' \
    ${tomcat_path}/conf/server.xml && color "虚拟主机配置成功" 0
    mkdir ${tomcat_path}/mxx${i}/ROOT -p
    chown tomcat.tomcat ${tomcat_path}/mxx$i -R
    cat > ${tomcat_path}/mxx$i/ROOT/index.jsp <<\EOF
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" http-equiv=Content-Type content="text/html;charset=utf-8">
    <title>tomcat test</title>
</head>
<body>
<h1> Tomcat Website </h1>
<div>On  <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>

<h1>这是一个测试页面</h1>
</body>
</html>
EOF
    systemctl restart tomcat.service
    done
}

#exec
jdk_install && tomcat_install && tomcat_config

测试结果

image.png
image.png

4、nginx实现后端tomcat的负载均衡调度

Nginx作为反向代理配置

配置nginx反向代理,将域名全部调度给后端tomcat服务器组,因为后端tomcat配置了虚拟主机,因此调度时修改了Host字段的值:

[root@centos8mini ~]# cat /data/nginx/conf/conf.d/server1.conf
server {
    listen 80;
    server_name m1.mxx.com;
    default_type text/html;
    root /data/server1;
#   location ~* \.jsp$  {
#       proxy_pass http://www.mxx.com:8080;
#       #proxy_set_header Host $http_host;
#   }
#   location ~* \.html$  {
#       proxy_pass http://blog.mxx.com:8080;
#       #proxy_set_header Host $http_host;
#   }
#   location /blog {
#       index index.jsp;
#       proxy_pass http://www.mxx.com:8080/blog;
#   }
    location / {
        index index.jsp;
        proxy_set_header Host www.mxx.com;
        proxy_pass http://webserver;
    }
}

在http语句块下定义服务器组,指向后端的两台tomcat服务器,调度算法也是在这里指定:

[root@centos8mini ~]# cat /data/nginx/conf/nginx.conf
...
http {
    upstream webserver {
        #hash $cookie_jsessionid consistent;
        server 192.168.1.12:8080 max_fails=3 fail_timeout=30s;
        server 192.168.1.14:8080 max_fails=3 fail_timeout=30s;
    ....
    }
...

测试结果

修改windows的hosts文件,解析m1.mxx.com域名,指向nginx代理服务器:

192.168.1.13 m1.mxx.com m2.mxx.com

没做session的会话保持前,调度到不同服务器会生成不同的session ID:

image.png

5、简述memcached的工作原理

Memcached采用Slab Allocator机制来分配、管理内存。根据提前定义好的Growth factor等参数,memcached启动后自动按照定义的参数分配内存空间并执行数据的存储。

memcached使用c/s架构,服务器维护key-value关联数组,客户端输入数据到数组中,并使用key来查询。
key可以有250字节长度,value可以存最大1M。

memcached内存空间是启动时提前分配好的。内存被分成大小相等的slab,然后每个slab被等分成chunk,slab按照chunk的大小进行分组,组成不同的slab class。

  • 一个1M大小内存空间作为一个slab,slab会等分成固定大小的chunk,但不同slab等分的chunk是不同的。处于相同层次的slab分配的chunk大小是相同的,不同层次按照growth factor来确定下一层次slab中chunk的大小。

当执行value存储时,memcached会根据value的大小,找到合适的chunk进行存储。

当内存不足时,memcached使用LRU(least recently used)机制来查找可用空间。memcached不会监视数据是否过期,而是采取Lazy Expiration懒过期机制,在取数据时才查看数据是否过期,过期就把数据有效期标识为0,但并不清理该数据,而是在以后直接覆盖该位置来存储其他数据。

memcached集群功能是基于客户端的分布式集群,客户端在生成数据时决定应该在哪里存放数据,memcached不会去执行数据的集群同步。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 1、搭建Tomcat集群,并通过nginx反向代理访问 反向代理示意图 测试环境: Nginx: 172.16.1...
    卫清华阅读 168评论 0 0
  • java动态网页技术 servlet 本质就是一段Java程序 在Servlet中最大的问题是,HTML输出和Ja...
    Liang_JC阅读 485评论 0 0
  • redis是什么 redis是一个非关系型数据库,以KV结构存储数据,提供了多种数据类型和各自的本地方法,单线程处...
    小丸子的呆地阅读 502评论 0 2
  • 后端架构师技术图谱 最后更新于20180502 数据结构队列集合链表、数组字典、关联数组栈树二叉树完全二叉树平衡二...
    01_小小鱼_01阅读 1,803评论 0 38
  • 数据结构队列集合链表、数组字典、关联数组栈树二叉树完全二叉树平衡二叉树二叉查找树(BST)红黑树B-,B+,B*树...
    jackcooper阅读 3,278评论 1 50