CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。
1、 准备好3台虚拟机搭建nginx和kafka集群
2、配置好静态ip地址,NAT模式可以跳过此步骤。
[root@nginx-kafka03 ~]# cat /etc/resolv.conf #配置好dns
# Generat ed by NetworkManager
nameserver 114.114.114.114
3、修改主机名、配置域名解析
vim /etc/hosthname #添加3台kafka服务器的ip对应的名字
hostname -F /etc/hostname 设置永久生效
vim /etc/hosts #配置域名解析,主机名与ip地址一一对应
#192.168.169.133 kafka-1
#192.168.169.134 kafka-2
#192.168.169.135 kafka-3
4、安装基本软件,解决依赖关系
yum install wget lsof vim -y
5、安装时间同步服务
#装时间同步服务
yum install chrony -y
#设置chronyd服务开机启动
systemctl enable chronyd
#设置chronyd服务立马启动
systemctl start chronyd
#设置时区
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
6、关闭防火墙、selinux
#关闭防火墙
systemctl stop firewalld #临时关闭
systemctl disable firewalld #开机不启动
#关闭selinux
setenforce 0 #临时关闭
sed -i '/^SELINUX=/ s/enforcing/disabled/' /etc/selinux/config #修改配置,永久关闭
Nginx提供静态访问页面
主配置文件: nginx.conf
... #全局块
events { #events块
...
}
http #http块
{
... #http全局块
server #server块
{
... #server全局块
location [PATTERN] #location块
{
...
}
location [PATTERN]
{
...
}
}
server
{
...
}
... #http全局块
}
1、全局块:配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。
2、events块:配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。
3、http块:可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使
4、server块:配置虚拟主机的相关参数,一个http中可以有多个server。
5、location块:配置请求的路由,以及各种页面的处理情况
用户的流量过来了,按照调度的策略将他们调度分散到后端的web服务器上。
调度算法
轮询算法(一视同仁,按顺序依次来round robin)
加权轮询(加权重)
ip hash
最小连接数(中间件和哪台web服务器连接次数少就安排到哪台。哪台工作得少就加到那台)
此时的中间件就充当负载均衡器(LB:load banlance)。
full NAT
中间件要保留访问用户的IP地址,这样后端的real server在接收到请求包的时候能获得到用户的ip地址 记录到log,否则日志里面的ip全是中间件的ip。
那么用户的ip放在哪里呢?
数据封装从应用层开始(http)——传输层(tcp,查看端口)——网络层(ip)——数据链路层(mac)
在http协议里面增加首部字段。在请求报文里面添加一个首部字段,写上user的ip地址。
[root@kafka-1 conf]# cat nginx.conf |egrep -v "#|^$"
worker_processes 2;
events {
worker_connections 2048;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $http_x_real_ip - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
keepalive_timeout 65;
upstream scapp {
server 192.168.0.190:80 weight=3;
server 192.168.0.191 weight=1;
server 192.168.0.192 weight=1;
}
server {
listen 8080;
server_name www.feng.com;
location / {
proxy_pass http://scapp;
proxy_set_header X-Real-IP $remote_addr; #在http请求报文里增加 X-Real-IP字段
}
}
server {
listen 80 default_server;
server_name www.sc.com;
access_log logs/sc.access.log main;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
scp远程拷贝文件
# 将文件传输到另一台机器上的root目录下
scp onkey_install_cjh.sh 192.168.0.194:/root
# 将文件夹传输到另一台机器上
scp -r onkey_install_cjh 192.168.0.194:/root
中间件 :与主体的业务没有太多关系,仅仅只是作为中间的转发。比如网站是整个业务的主体,保证主体正常运行就行。日志收集和清洗不影响主体,网站是直观的创造价值,kafka只是通过它进行一定的分析,反补网站,让它更加的健康、灵活。
消息中间件:redis、rabbitmq、nsq、kafaka
消息中间件(kafka)作用:
kafka用在哪里——业务解耦、流量削锋、日志收集
这里引用kafka目的:
指的是由生产者将数据源源不断推送到消息中心,由不同的消费者从消息中心取出数据做自己的处理,在同一类别下,所有消费者拿到的都是同样的数据;
点对点:生产者消费者一一对应,消费者消费完,消息中间件就没有了;
发布-订阅 :本质上也是一种生产消费者模式,不同的是,由订阅者首先向消息中心指定自己对哪些数据感兴趣,发布者推送的数据经过消息中心后,每个订阅者拿到的仅仅是自己感兴趣的一组数据。这两种模式是使用消息中间件时最常用的,用于功能解耦和分布式系统间的消息通信。
kafka 使用发布-订阅的消息传递方式
副本的选举(partition选举leader):生产者跟partition的leader打交道的,leader同步到follwer里面去。消费者去leader里面去消费。follwer仅仅只是用来备份。leader挂了后follower之间就要重新选举leader。leader挂了才会重新选举。
ISR( in-sync-replica ) 集合列表。需要同步的follower集合
比如说5个副本,1个leader, 都在ISR里面
有一条消息来了,leader 怎么知道要同步哪些副本呢?根据ISR来。
如果一个follower挂了,那就从这个列表里面删除了。
如果一个follower卡住或者同步过慢,他也会从ISR里删除
数据的一致性保持
取决于生产者,生产者数据写入kafka一般都会有一个标志位,通过request.required.acks来设置数据可靠性的级别:
kafka是如何保证数据一致性?
消费组 多个消费者组成一个大的消费组来消费一类消息。
kafka是如何保证高可用的?
副本层面:多个broker+多个partition+多个replica
机器层面:ISR机制
1、安装java环境,因为kafka是java语言编写的
yum install java -y
2、下载kafka源码
mkdir -p /opt
wget http://mirrors.bfsu.edu.cn/apache/kafka/2.8.1/kafka_2.12-2.8.1.tgz
#解压到/opt目录下
tar xf kafka_2.12-2.8.1.tgz -C /opt
#修改环境变量PATH,添加kafka的bin目录
echo "PATH=$PATH:/opt/kafka_2.12-2.8.1/bin/" >>/root/.bashrc
3、修改kafka配置
#修改kafka的配置文件
cd /opt/kafka_2.12-2.8.1/config
#修改config /server.properties:
broker.id=0 #随机,但不能冲突,可以是主机名的最后一位
listeners=PLAINTEXT://kafka-1:9092 # 这里要和主机名保持一致
zookeeper.connect=192.168.0.94:2181,192.168.0.95:2181,192.168.0.96:2181 # 添加所有kafka集群的ip地址
4、启动kafka
注: 开启zk和kafka的时候,一定是先启动zk,再启动kafka;
关闭服务的时候,kafka先关闭,再关闭zk;
bin/kafka-server-start.sh -daemon config/server.properties
或
/opt/kafka_2.12-2.8.1/bin/kafka-server-start.sh -daemon /opt/kafka_2.12-2.8.1/config/server.properties &
zookeeper是一个分布式、开源的配置管理服务。
kafka版本: 2.8.1
zookeeper版本: 3.6.3
机器存活半数 ,少数服从多数。
端口说明:
2181:对终端提供服务
3888:提供集群交互的
2888:提供检验数据存活
保存kafka的元数据( topic、副本信息、选举controller )
选一个kafka集群controller来协调副本的leader、follower的选举;
controller是如何产生的?
通过抢占的方式选举,先到先得。
[zk: localhost:2181(CONNECTED) 8] get /controller
{"version":1,"brokerid":0,"timestamp":"1642300717047"}
log.dirs=/tmp/kafka-logs # kafka日志存放位置
num.partitions=1 # partition默认数量
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes==102400
kafka的日志可以按照俩个维度来设置保存:
1、按时间
2、按大小
kafka日志保存时按段保存的 segment
任意一个条件满足了都可以出发日志清理;
假如有以下的segment:00.log、11.log、22.log
00.log 保存的是1-11条的日志
11.log 保存的是12-22条的日志
22.log 保存的是23-33条的日志
[zk: localhost:2181(CONNECTED) 0] ls / #zookeeper 保留kafka的元数据,
[admin, brokers, cluster, config, consumers, controller, controller_epoch, feature, isr_change_notification, latest_producer_id_block, log_dir_event_notification, zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /brokers
[ids, seqid, topics]
[zk: localhost:2181(CONNECTED) 2] ls /brokers/ids # 查看左右
[0, 1, 2]
[zk: localhost:2181(CONNECTED) 5] get /brokers/ids/0 # 查看具体的 id信息
{"listener_security_protocol_map":{"PLAINTEXT":"PLAINTEXT"},"endpoints":["PLAINTEXT://kafka-1:9092"],"jmx_port":-1,"features":{},"host":"kafka-1","timestamp":"1642300716774","port":9092,"version":5}
[zk: localhost:2181(CONNECTED) 6] ls /brokers/topics # 查看主题
[__consumer_offsets, sc] # __consumer_offsets消费者的偏移量
消费者消费完成之后会有一个偏移量的设置。偏移量可以就保存在消费者本地,也可以保存在kafka服务端;
[zk: localhost:2181(CONNECTED) 7] get /brokers/topics/__consumer_offsets # 目前消费者的偏移量保存在zookeepr上面
{"removing_replicas":{},"partitions":{"30":[2],"39":[2],"45":[2],"2":[0],"5":[0],"48":[2],"33":[2],"27":[2],"12":[2],"8":[0],"15":[2],"42":[2],"36":[2],"21":[2],"18":[2],"24":[2],"35":[0],"41":[0],"7":[1],"17":[0],"1":[1],"44":[0],"23":[0],"38":[0],"47":[0],"4":[1],"26":[0],"11":[0],"32":[0],"14":[0],"20":[0],"29":[0],"46":[1],"34":[1],"28":[1],"6":[2],"40":[1],"49":[1],"9":[2],"43":[1],"0":[2],"22":[1],"16":[1],"37":[1],"19":[1],"3":[2],"10":[1],"31":[1],"25":[1],"13":[1]},"topic_id":"tH33a61KTemNxdQ9vcnq3g","adding_replicas":{},"version":3}
生产者发送消息的时候 ,随机挑选任一一台都可以,会有协商。这个broker会返回给你副本的leader信息,生产者再跟leader交互。
1、下载zookeeper源码、解压
cd /opt
#下载zookeeper源码
wget http://mirrors.bfsu.edu.cn/apache/zookeeper/zookeeper-3.6.3/apache-zookeeper-3.6.3-bin.tar.gz
#解压zookeeper源码文件
tar xf apache-zookeeper-3.6.3-bin.tar.gz
2、修改zookeeper的配置文件
cd /opt/apache-zookeeper-3.6.3-bin/conf
#修改PATH变量
echo "PATH=/opt/apache-zookeeper-3.6.3-bin/bin:$PATH" >>/root/.bashrc
#根据样例配置,生成一个主配置文件
cp zoo_sample.cfg zoo.cfg
#在zoo.cfg配置文件后面追加配置
#3888和4888都是端口 一个用于数据传输,一个用于检验存活性和选举
#server.1=192.168.169.133:3888:4888
#server.2=192.168.169.134:3888:4888
#server.3=192.168.169.134:3888:4888
3、创建/tmp/zookeeper目录 ,在目录中添加myid文件,文件内容就是本机指定的zookeeper id内容
#在myid文件里写入和zoo.cfg配置文件里的ip对应的server数字
#在192.168.139.133机器上
echo 0 > /tmp/zookeeper/myid
#在192.168.139.134机器上
echo 1 > /tmp/zookeeper/myid
#在192.168.139.135机器上
echo 2 > /tmp/zookeeper/myid
4、启动zookeeper
bin/zkServer.sh start
或
/opt/apache-zookeeper-3.6.3-bin/bin/zkServer.sh start
5、查看状态
bin/zkServer.sh status #相对路径
或
/opt/apache-zookeeper-3.6.3-bin/bin/zkServer.sh status #绝对路径
filebeat 相当于一个收集机器,监控nginx日志,日志一旦发生了变化就会涂到kafka里面去。
filebeat是Beats中的一员;
Beats在是一个轻量级日志采集器,其实Beats家族有6个成员,早期的ELK架构中使用Logstash收集、解析日志,但是Logstash对内存、cpu、io等资源消耗比较高。相比Logstash,Beats所占系统的CPU和内存几乎可以忽略不计。
Filebeat是用于转发和集中日志数据的轻量级传送工具。Filebeat监视您指定的日志文件或位置,收集日志事件,并将它们转发到Elasticsearch或 Logstash进行索引
1.安装源,导入官方的GPG-key文件
rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch
2.新建和编辑/etc/yum.repos.d/fb.repo文件
[elastic-7.x]
name=Elastic repository for 7.x packages
baseurl=https://artifacts.elastic.co/packages/7.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
3.yum安装filebeat
yum install filebeat -y
rpm -qa |grep fileberat #可以查看filebeat有没有安装 rpm -qa 是查看机器上安装的所有软件包
rpm -ql filebeat #查看filebeat安装到哪里去了,牵扯的文件有哪些
4.设置开机自启
systemctl enable filebeat
5.配置
#ymal格式 转json用的
{
"filebeat.inputs": [
{ "type":"log",
"enabled":true,
"paths":["/var/log/nginx/sc_access"
},
],
}
修改配置文件/etc/filebeat/filebeat.yml(先备份后清空再重新编辑)
filebeat.inputs: #注:格式一定不能错,否则无法消费
- type: log
# Change to true to enable this input configuration.
enabled: true
# Paths that should be crawled and fetched. Glob based paths.
paths:
- /var/log/nginx/sc_access.log
#==========------------------------------kafka-----------------------------------
output.kafka:
hosts: ["192.168.169.133:9092","192.168.169.134:9092","192.168.169.135:9092"]
topic: nginxlog
keep_alive: 10s
6.创建主题nginxlog
bin/kafka-topics.sh --create --zookeeper 192.168.169.133:2181 --replication-factor 3 --partitions 1 --topic nginxlog #创建3个副本,一个分区
7.重启filebeat服务
systemctl restart filebeat
[root@nginx-kafka01 opt]# ps -ef |grep filebeat
root 5537 1 0 15:32 ? 00:00:08 /usr/share/filebeat/bin/filebeat
--environment systemd -c /etc/filebeat/filebeat.yml
--path.home /usr/share/filebeat
--path.config /etc/filebeat
--path.data /var/lib/filebeat # /var/lib/filebeat/registry/filebeat/log.json filebeat数据文件
--path.logs /var/log/filebeat
8.创建消费者
bin/kafka-console-consumer.sh --bootstrap-server 192.168.169.133:9092 --topic nginxlog --from-beginning
在kafka服务器里创建nginxlog的topic,同时设置3个副本,1个分区
bin/kaa-topics.sh --create --zookeeper 192.168.169.133:2181 --replication-factor 3 --partitions 1 --topic nginxlog
#把字符串dt转成时间格式
timeArray = time.strptime(dt, "%d/%b/%Y:%H:%M:%S")
#timeStamp = int(time.mktime(timeArray))
#把时间格式转成字符串
new_time = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
提取出的ip字段通过淘宝的一个接口解析出省份和运营商
url = “https://ip.taobao.com/outGetIpInfo?accessKey=alibaba-inc&ip=114.114.114.114”
import requests
url = "http://ip.aliyun.com/outGetIpInfo?accessKey=alibaba-inc&ip=114.119.156.146"
response = requests.get(url)
print(response.text)