新秀网关-Apache-APISIX--初探

    技术2022-07-11  82

    文章已收录 架构技术专栏 收藏不迷路,点击获取更多视频资料福利

    一、概述

    最近有工作需求需要搞一个网关来给我们的应用做路由、限流等等功能。以前使用的Spring Cloud Zuul做网关,但目前的技术体系如果要用它就比较繁琐点了,所以又看了看其他的,发现Apisix 这货很不错啊。主要是KONG忒复杂了,Apisix很轻量很简单的样子,看起来不错,下面看下和KONG的官方对比。

    功能Apache APISIXKONG项目归属Apache 软件基金会Kong Inc.技术架构Nginx + etcdNginx + postgres单核 QPS (开启限流和prometheus插件)180001700平均延迟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,我喜欢给他设置80admin_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。

    恭喜你,完成初步体验。

    Processed: 0.015, SQL: 9