为什么必须配置hosts文件映射-hostname问题整理
1. 一些问题先来思考一下以下几个问题:hostname和域名的区别是什么?为什么kafka服务端server.properties中如果配置了hostname,则客户端的/etc/hosts就必须配置服务端的ip和hostname的映射?为什么storm集群环境必须配置集群所有机器的ip和hostname的映射?2. 基本概念要回答以上几个问题,我们先来弄清楚几个基本概念。...
1. 一些问题
先来思考一下以下几个问题:
- hostname和域名的区别是什么?
- 为什么kafka服务端server.properties中如果配置了hostname,则客户端的/etc/hosts就必须配置服务端的ip和hostname的映射?
- 为什么storm集群环境必须配置集群所有机器的ip和hostname的映射?
2. 基本概念
要回答以上几个问题,我们先来弄清楚几个基本概念。
2.1 hostname
- hostname也就是主机名,表示在一个特定网络范围内的一个计算机的名字
- 每个主机都会有自己的hostname,在一个特定的网络范围内唯一
- 每个主机都会有自己的ip地址,在一个特定的网络范围内唯一
比如xx系统的一个联机服务节点,运行在生产核心区的一台虚机上,该虚机的主机名是dcsapp17,也就是其hostname是dcsapp17。
2.2 域名
- 域名是因特网范围内某一个服务器的名字,是用来解决IP地址不可读不好记的问题
- 每个域名都对应一个具体的主机
- 域名本身有自己的命名系统和层级规范,但其本质是为了按照一种通用的约定,标识因特网中的一台主机
例如baidu.com这个域名,就代表了百度的一台服务器,通过ping可以看到其代表主机信息
ping baidu.com
PING baidu.com (123.125.114.144): 56 data bytes
64 bytes from 123.125.114.144: icmp_seq=0 ttl=48 time=25.982 ms
64 bytes from 123.125.114.144: icmp_seq=1 ttl=48 time=25.990 ms
大型网站在多服务器负载均衡的情况下,一个域名可能会以对应多个ip地址,但是DNS一定会将其解析成某一个IP地址
2.3 域名解析
- 当我们希望往某个域名发送请求的时候,需要将域名映射为实际的ip地址,这个过程称之为域名解析
- 专门用来做域名解析的服务,称之为DNS服务,相应的有DNS服务器
- 根据DNS服务器服务范围的不同,可以分为互联网DNS服务器和局域网DNS服务器
- 局域网不一定需要DNS服务器,只要当前主机的/etc/hosts中配置了其他主机的ip地址和hostname的映射,则当前主机就可以通过主机名或者域名来访问对应的机器
域名解析的过程
请求某个域名下的一个url,域名解析的过程大致为:
- 检查缓存中有没有这个域名对应的解析过的ip地址,如果有则返回。缓存的时间、大小都可以配置
- 如果缓存没有,OS检查本地的hosts文件中有没有对应的映射关系,如果有,则以配置的hosts映射为准,返回
- 如果hosts里没有,则查找本地DNS服务器缓存,是否有对应的解析过的ip地址,如果有,返回(根据策略配置,可能还会缓存到本机)
- 如果没有,则会到配置的首选DNS服务器上去查询解析,查询到,则返回
- 如果首选DNS服务器上仍然没有,则根据规则,进行一层层DNS查询转发,直到找到
解析过程还有很多细节,根据不同的策略配置会有不同的路径,但是整体上类似
无论请求的url中是域名还是hostname,其本质都是使用别名替代了原有的ip地址,在请求路由的时候,要么是hosts映射文件,要么是各种级别的DNS服务器,总要将别名解析为具体的ip地址,才可以将请求发送到目的地。
3. 应用中的hostname
我们发布的每一个网络服务,其底层通讯通常都是基于TCP/IP协议:OS在本地监听某个端口,客户端主机可以通过服务所在的ip和端口请求建立链接并交换数据:
- 在启动监听的时候,以java网络应用程序为例,无论是原生的ServerSocket还是netty中的的nio,都是指定端口即可
- 当客户端请求连接的时候,需要提供服务端的ip地址和端口;即使某些API支持通过hostname建立链接,其内部一定还是通过hosts映射或者dns解析出目标ip并发起建链请求
越来越多的开源通讯组件如dubbo、storm、kafka等在设计时,一般都会考虑如下几个原则:
- 基于服务注册发现机制,即服务提供者都是将自己的元信息注册到服务注册中心,然后客户端访问注册中心,从而获取服务提供者的主机信息,进而再请求与服务提供者建立链接
- 在服务注册发现时,推荐使用hostname而不是ip地址,原因是hostname更具有可读性且在云环境下如果需要,可以保证在不更改hostname的情况下替换ip地址,从而客户端应用无需修改配置
- 客户端从注册中心获取到hostname之后,需要通过dns或者本地hosts映射文件,将hostname解析成ip地址,进而请求建立链接和后续服务
接下来我们看看kafka、storm在设计的时候是怎么做的。
3.1 kafka中的hostname
kafka中的broker的监听配置如下
# The address the socket server listens on. It will get the value returned from
# java.net.InetAddress.getCanonicalHostName() if not configured.
# FORMAT:
# listeners = listener_name://host_name:port
# EXAMPLE:
# listeners = PLAINTEXT://your.host.name:9092
listeners=PLAINTEXT://172.21.132.66:49092
# Hostname and port the broker will advertise to producers and consumers. If not set,
# it uses the value for "listeners" if configured. Otherwise, it will use the value
# returned from java.net.InetAddress.getCanonicalHostName().
#advertised.listeners=PLAINTEXT://your.host.name:9092
- listeners:kafka的连接协议名、主机名和端口,如果没有配置,将使用
java.net.InetAddress.getCanonicalHostName()
的返回值作为主机名 - advertised.listeners:生产者和消费者使用的主机名和端口,如果没有配置,将使用listeners的配置,如果listeners也没有配置,将使用
java.net.InetAddress.getCanonicalHostName()
的返回值
以上的配置,在kafka broker启动的时候,会将配置的信息注册到zookeeper并在集群中维护自己的元信息。当客户端与broker建立链接时,broker会将此处配置的信息返回给客户端,然后客户端会根据需要向某个broker节点发起建链请求。
因此,如果这里配置的hostname,则返回给客户端的broker信息便是hostname;如果配置的是ip地址,则返回给客户端的broker信息便是ip地址。如果客户端拿到的是hostname,则在建立链接的时候,便要将hostname解析成ip地址,假设此时hosts映射文件或者dns服务器中没有相关的解析配置,则客户端无法建立链接。
这里需要指出的是,无论是生产者还是消费者,我们配置的bootstrap.servers
都是引导地址,而不是客户端真正建立长链接的地址。也就是说,客户端会根据引导地址去broker询问集群的所有broker信息,拿到返回的broker服务信息之后,再向指定的broker发起链接请求。因此bootstrap.servers
无论配置的是ip还是hostname,都是只作为引导信息发起查询请求而已。
3.2 storm中的hostname
storm是比较流行的流式计算引擎,在storm集群中,每个负责执行计算任务的节点称为Supervisor节点,每个Supervisor启动的时候,将自己注册到zookeeper,当任务分发时,Supervisor从zk中获取到自己的上下游Supervisor节点并与之建立链接,形成流式计算任务序列,一个任务在一个计算节点处理完则被发送到下一个任务处理节点。
在storm中,Supervisor启动时,也是先读取配置文件,当配置文件不存在时,使用netAddress.getLocalHost().getCanonicalHostName()的返回值作为hostname并将其注册到zookeeper。
部分hostname解析逻辑如下:
protected String hostnameImpl () throws UnknownHostException {
if (localConf == null) {
return memoizedLocalHostname();
}
Object hostnameString = localConf.get(Config.STORM_LOCAL_HOSTNAME);
if (hostnameString == null || hostnameString.equals("")) {
return memoizedLocalHostname();
}
return (String)hostnameString;
}
protected String localHostnameImpl () throws UnknownHostException {
return InetAddress.getLocalHost().getCanonicalHostName();
}
因此在storm中,需要在集群的每个节点的hosts中配置彼此的hostname和ip的映射,以在需要的时候完成hostname解析。
4. 问题解答
综上,我们可以回答文章开头的问题:
- hostname和域名的区别是什么?
- hostname和域名都是为了解决ip地址不方便阅读和记忆的问题,前者在局域网内唯一,后者在因特网内唯一
- 在发起链接请求时,需要根据hosts配置或者不同层级的dns服务器将hostname或者域名解析为具体的ip地址
- 为什么kafka服务端server.properties中如果配置了hostname,则客户端的/etc/hosts就必须配置服务端的ip和hostname的映射?
- kafka broker将配置的hostname作为服务器的元信息存储在zk和broker集群
- 客户端通过引导地址访问broker之后,broker返回给客户端的是用户配置的服务信息,如果配置的是hostname,则客户端拿到的就是hostname;如果配置的是ip地址,则客户端拿到的就是ip地址
- 客户端向服务端发起建链请求,需要将hostname解析成具体的ip地址。在没有局域网dns服务其的情况下,hosts映射文件就是一个本地的dns服务
- 为什么storm集群环境必须配置集群所有机器的ip和hostname的映射?
- storm的计算节点在启动时候会注册到zk,如果配置文件包含"storm.local.hostname",那么就使用配置的主机名;否则通过调用InetAddress.getLocalHost().getCanonicalHostName()获取主机名
- storm的计算节点在请求和其他计算节点建立链接的时候,先通过zk获取到主机名,然后发起建立链接的请求。如果拿到的是hostname,则需要hosts映射或者dns服务将其解析成ip地址
需要说明的是,只要hostname能够被解析成ip地址即可,当前在生产环境有时候必须配置hsotname,是因为没有提供局域网dns服务器。随着后续dns服务器的配套完善,就不一定非要配置hosts映射文件了。
更多推荐
所有评论(0)