新秀网关-Apache-APISIX--初探
文章已收录 架构技术专栏 收藏不迷路,点击获取更多视频资料福利
一、概述
最近有工作需求需要搞一个网关来给我们的应用做路由、限流等等功能。以前使用的Spring Cloud Zuul做网关,但目前的技术体系如果要用它就比较繁琐点了,所以又看了看其他的,发现Apisix 这货很不错啊。主要是KONG忒复杂了,Apisix很轻量很简单的样子,看起来不错,下面看下和KONG的官方对比。
功能 | Apache APISIX | KONG |
---|---|---|
项目归属 | Apache 软件基金会 | Kong Inc. |
技术架构 | Nginx + etcd | Nginx + postgres |
单核 QPS (开启限流和prometheus插件) | 18000 | 1700 |
平均延迟 | 0.2 毫秒 | 2 毫秒 |
支持 Dubbo 代理 | 是 | 否 |
配置回滚 | 是 | 否 |
支持生命周期的路由 | 是 | 否 |
插件热更新 | 是 | 否 |
用户自定义:负载均衡算法、路由 | 是 | 否 |
resty <–> gRPC 转码 | 是 | 否 |
支持 Tengine 作为运行时 | 是 | 否 |
MQTT 协议支持 | 是 | 否 |
配置生效时间 | 事件通知,低于1毫秒更新 | 定期轮询,5 秒 |
自带控制台 | 是 | 否 |
对接外部身份认证服务 | 是 | 否 |
配置中心高可用(HA) | 是 | 否 |
指定时间窗口的限速 | 是 | 否 |
支持任何 Nginx 变量做路由条件 | 是 | 否 |
嗯~ 看了上面的介绍,感觉这玩意真是溜的飞起来啊,赶紧来试一波。
二、安装
官方那安装文档就不吐槽了,反正真使用起来也是一脸懵逼,下面就根据源码安装来说下。因为是Mac,所以举例也是Mac的。
1、安装openresty 和 etcd
# install OpenResty, etcd and some compilation tools
brew install openresty/brew/openresty etcd luarocks curl git
# start etcd server with v2 protocol
etcd --enable-v2=true &
2、下载APISIX 源码并编译
#下载1.4源码
wget http://www.apache.org/dist/incubator/apisix/1.4/apache-apisix-1.4-incubating-src.tar.gz
tar zxvf apache-apisix-1.4-incubating-src.tar.gz
#进行lua 依赖下载,注意下载的os文件是mac的,如果你部署在linux 最好在linux 执行这个命令
cd apache-apisix-1.4-incubating
make deps
# 上面源码包就打完了,但里面不带dashboard.所以我们还得下载个dashboard进行打包(注意,如果你使用git clone的话,就可以使用git submodule update --init --recursive命令进行dashboard下载了)
这里我直接下载1.4对应的dashboard
wget https://github.com/apache/incubator-apisix-dashboard/archive/329b092dcaa7a505dcdec86c667b6803f5863d94.zip
unzip 329b092dcaa7a505dcdec86c667b6803f5863d94.zip
cd incubator-apisix-dashboard-329b092dcaa7a505dcdec86c667b6803f5863d94/
#然后下载完毕,我们就开始对dashboard进行打包了,这里注意下,你的 Node.js 版本必须在8.12.0 或更高,具体初始化请查看 https://yarnpkg.com/en/docs/install
#现在开始初始化依赖了
yarn install
#在给它编译下
yarn run build:prod
#编译完成后,文件在dist目录下,我们将打好的 dist目录下的内容全部拷贝到apache-apisix-1.4-incubating/dashboard目录下
如图:
3、编辑apisix的配置文件
apisix的配置文件在conf/config.yaml,一般测试不需要改什么,默认的就可以,下面说下需要注意的几个属性
- allow_admin 代表允许访问dashboard的地址
- node_listen APISIX监听地址,默认9080,我喜欢给他设置80
- admin_key 你登录和REST接口需要的
- etcd host 配置你etcd地址,默认我们本机,上面已经启动了
- etcd prefix 可以简单理解为哪个库
- plugins 所有的插件,在你配置时候可以选择
4、启动APISIX
#初始化配置
make init
#出现以下信息表示完成
#./bin/apisix init
#./bin/apisix init_etcd
#这时候会在conf目录下出现nginx.conf 这就是真正的配置
#然后就可以启动了
make run
#出现以下信息代表启动成功
#mkdir -p logs
#mkdir -p /tmp/apisix_cores/
#/usr/local/bin/openresty -p $PWD/ -c $PWD/conf/nginx.conf
现在我们就可以访问配置页面了,http://127.0.0.1:9080/apisix/dashboard
注意:如果你使用http://localhost:9080/apisix/dashboard访问,不好意思,会403,这个就是我们allow\_admin的配置,当然你也可以注释掉。
正常访问后,我们就会看到如下的登录页面了
三、使用
1、安装完了,就来测试下吧,登录进来就可以看到整个配置页面
2、我们这里只关心Upstream 和Routes两个菜单
- Routes 用于配置路由策略
- Upstream 用于配置转发策略
3、配置Upstream
点击添加,我们来添加一个应用(这个配置是一个基础配置,没有人引用的话没什么意义)
4、配置Routes
点击Routes -》 添加,我们来添加一个路由规则,如图
5、测试
好了,大功告成,下面我们就写个简单的接口测试下。
//自己去搞个工程,下面是controller
@RestController
@RequestMapping("/check")
@CrossOrigin
public class CheckController {
@RequestMapping("/getIp")
public String getIp(HttpServletRequest request){
Map<String,Object> datas = new HashMap<>(16);
datas.put("OsName", OSUtil.getOsName());
datas.put("ProcessNo", OSUtil.getProcessNo());
datas.put("RealIp", OSUtil.getRealIp(request));
datas.put("HostName", OSUtil.getHostName());
return JSON.toJSONString(datas);
}
}
辅助工具类
public class OSUtil {
private static volatile String OS_NAME;
private static volatile String HOST_NAME;
private static volatile List<String> IPV4_LIST;
private static volatile int PROCESS_NO = 0;
public static String getOsName() {
if (OS_NAME == null) {
OS_NAME = System.getProperty("os.name");
}
return OS_NAME;
}
public static String getHostName() {
if (HOST_NAME == null) {
try {
InetAddress host = InetAddress.getLocalHost();
HOST_NAME = host.getHostName();
} catch (UnknownHostException e) {
HOST_NAME = "unknown";
}
}
return HOST_NAME;
}
/** * 获取系统环境变量分隔符 * * @return */
public static String getPathSeparator() {
return System.getProperty("path.separator");
}
public static List<String> getAllIPV4() {
if (IPV4_LIST == null) {
IPV4_LIST = new LinkedList<String>();
try {
Enumeration<NetworkInterface> interfs = NetworkInterface.getNetworkInterfaces();
while (interfs.hasMoreElements()) {
NetworkInterface networkInterface = interfs.nextElement();
Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
while (inetAddresses.hasMoreElements()) {
InetAddress address = inetAddresses.nextElement();
if (address instanceof Inet4Address) {
String addressStr = address.getHostAddress();
if ("127.0.0.1".equals(addressStr)) {
continue;
}
IPV4_LIST.add(addressStr);
}
}
}
} catch (SocketException e) {
}
}
return IPV4_LIST;
}
public static String getRealIp(HttpServletRequest request){
// 获取客户端ip地址
String clientIp = request.getHeader("x-forwarded-for");
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getHeader("Proxy-Client-IP");
}
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getHeader("WL-Proxy-Client-IP");
}
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getRemoteAddr();
}
/* * 对于获取到多ip的情况下,找到公网ip. */
String sIP = null;
if (clientIp != null && !clientIp.contains("unknown") && clientIp.indexOf(",") > 0) {
String[] ipsz = clientIp.split(",");
for (String anIpsz : ipsz) {
if (!isInnerIP(anIpsz.trim())) {
sIP = anIpsz.trim();
break;
}
}
/* * 如果多ip都是内网ip,则取第一个ip. */
if (null == sIP) {
sIP = ipsz[0].trim();
}
clientIp = sIP;
}
if (clientIp != null && clientIp.contains("unknown")){
clientIp =clientIp.replaceAll("unknown,", "");
clientIp = clientIp.trim();
}
if ("".equals(clientIp) || null == clientIp){
clientIp = "127.0.0.1";
}
return clientIp;
}
/** * 判断IP是否是内网地址 * @param ipAddress ip地址 * @return 是否是内网地址 */
public static boolean isInnerIP(String ipAddress) {
boolean isInnerIp;
long ipNum = getIpNum(ipAddress);
/** 私有IP:A类 10.0.0.0-10.255.255.255 B类 172.16.0.0-172.31.255.255 C类 192.168.0.0-192.168.255.255 **/
long aBegin = getIpNum("10.0.0.0");
long aEnd = getIpNum("10.255.255.255");
long bBegin = getIpNum("172.16.0.0");
long bEnd = getIpNum("172.31.255.255");
long cBegin = getIpNum("192.168.0.0");
long cEnd = getIpNum("192.168.255.255");
isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd)
|| ipAddress.equals("127.0.0.1");
return isInnerIp;
}
private static boolean isInner(long userIp, long begin, long end) {
return (userIp >= begin) && (userIp <= end);
}
private static long getIpNum(String ipAddress) {
String[] ip = ipAddress.split("\\.");
long a = Integer.parseInt(ip[0]);
long b = Integer.parseInt(ip[1]);
long c = Integer.parseInt(ip[2]);
long d = Integer.parseInt(ip[3]);
return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
}
public static int getProcessNo() {
if (PROCESS_NO == 0) {
try {
PROCESS_NO = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
} catch (Exception e) {
PROCESS_NO = -1;
}
}
return PROCESS_NO;
}
}
启动我们的工程,我们工程配置的启动端口是6080,这时我们使用我们的网关去进行转发访问,
http://127.0.0.1:9080/check/getIp,返回如下信息:
{“ProcessNo”:18944,“OsName”:“Mac OS X”,“HostName”:“luqiangdeMacBook-Pro.local”,“RealIp”:“127.0.0.1”}
上面通过访问apisix 进行了请求转发,将/check/getIp 转发到了localhost 6080。
恭喜你,完成初步体验。
还没有评论,来说两句吧...