转自:http://blog.54im.com/2016/12/15/centos-install-kong-cassandra/#
前置阅读
对于一些传统的大型项目,传统的方式会有一些缺陷,比如说新人熟悉系统成本高(因为整个系统作为一个整体,彼此会有一定的牵连),项目重启时间长,重构困难(对于一个新技术的引入,可能需要对整个项目推到重来),不易于更换新的技术,并且整个项目会慢慢变成巨无霸。
近年来微服务受到越来越多国内企业的青睐。当企业现有系统的复杂度、维护和扩展成本成为业务发展瓶颈时,微服务可以帮助企业拆分、解耦现有的系统,从而提高系统的可维护和可扩展性。Airbnb、DropBox、Twitter等互联网公司,在使用微服务架构之后,功能发布周期减少了75%,微服务的核心在于根据业务和具体粒度划分API,那么如何管理API就显得尤为重要。
拿日常的电商购物举例,一个服务实现一个不同的特性或者功能。每一个独立的微服务都是一个小型应用。一些微服务可能会暴露一些api 给其他的一些微服务或者是客户。
购物车,商品详情,支付等模块分别提供单独的rest api接口,给上层访问。所有的请求前面有统一的入口,api网关负责路由,认证,性能分析等功能
当然,微服务也有一定的缺陷,比如说每个服务(每个应用) 如果都有一个数据库的话,那么如何维持数据库事务。再比如说,服务之间的调用可能会由于网络的原因变得不可达,那么代码中要额外增加请求失败的代码。运维维护成本升高,开发时需注意模块间耦合。
上面这个架构其实很容易看出,api网关很容易成为性能瓶颈,而且也存在单点。api层面耦合太高。
架构调整
引入Kong做api网关
微服务上层会有许多消费者(网站、移动端、甚至物联网设备),而这些消费者可能会依赖一些共同的基础服务,kong可以作为API网关提供一些插件来实现这些基础功能,比如登录,权限认证等。
Kong简介
Kong是Mashape开源的一款API网关,起初是用来管理 Mashape 公司15000个微服务的,后来在2015年开源,现在已经在很多创业公司、大型企业和政府机构中广泛使用。基于Lua和Cassandra或Postgresql,支持分布式操作,有很强的可移植性和可扩展性。可以在任何一种基础设施上运行,作为应用和API之间的中间层,加上众多功能强大的插件,可以实现认证授权、访问控制等功能。并且提供易于使用的RESTful API来操作和配置系统。
Kong可以说是API的得力助手。对需要从事API管理的广大开发员来说,它是最出色的工具之一。多年来,Kong一直在支持优秀的开发项目,比如Mashape(世界上规模最大的API市场)。最棒的是,Kong得到了强大的Nginx的支持。MaxCDN也将Mashape与其无限恶意软件扫描器(Infinite Malware Scanner)结合使用,用来检测其内容分发网络(CDN)上的恶意软件。
https://github.com/Mashape/kongstart 7k+
Kong的主要功能
Kong可灵活扩展:你可以通过增加更多Kong Server机器对Kong服务进行水平扩展,通过前置的负载均衡器向这些机器分发请求。这样就可以支持更多流量,同时确保网络延迟很短。根据文档描述,两个Cassandra节点就足以支撑绝大多数情况,但如果网络非常拥挤,可以考虑适当增加更多节点。
Kong可在任何地方运行:它可以部署在单个或多个数据中心环境的私有云或公有云上。它还支持大多数流行的操作系统,比如Linux、Mac和Windows。Kong包括许多实用技巧,以便针对大多数现代平台完成安装和配置工作。
Kong具有模块性:它可以与新的插件协同运行,扩展基本功能。可将你的API与许多不同的插件整合起来,这些插件在API请求响应循环的生命周期中被执行。插件使用Lua编写,而且Kong还有如下几个基础功能:HTTP基本认证、密钥认证、CORS( Cross-origin Resource Sharing,跨域资源共享)、TCP、UDP、文件日志、API请求限流、请求转发以及Nginx监控。以增强安全、分析、验证、日志及/或监测机制。最好的例子之一就是Nginx Plus插件(https://getkong.org/plugins/nginx-plus-monitoring/),该插件提供了服务器实时监测机制,以获得关于负载和请求的度量指标和统计数字。
请求工作流
为了更好地理解系统,这是使用Kong的API的典型请求工作流:
Kong提供认证,限流,负载均衡等功能
- Mashapoe Marketplace
- Buzzlogix
- Gengo
- IBM
- Intel
- OpenDNS
- 饿了么
它是如何工作的?
Kong可与两种不同的组件协同工作:
- Nginx:Kong使用经过修改的Nginx web服务器作为代理服务器,该服务器负责处理API请求。
- Apache Cassandra或者Postgresql:这用作数据存储(Datastore)服务器,负载存储来自Kong操作的数据。
Kong VS 其他API网关
- 开源:没有黑盒。 对于企业或免费使用,Kong是完全开源的。
- 基于Nginx:Kong嵌入在Nginx并受益于其令人惊叹的代理性能。
- 可定制:编写插件以涵盖您的所有架构用例。
- 数据所有权:Kong及其基础数据存储在您的服务器上运行。
- 容易扩展:所有孔节点是无状态的。 在你的集群中产生新的节点是很容易的。
- 集成:许多插件与微服务世界中的流行的第三方服务集成。
kong性能数据
官方在AWS上进行性能测试, Kong运行在三个m3.medium EC2实例上; 一个用于部署Kong Server,一个用于Cassandra做数据存储,另一个用于上游API。 在将上游API的upstream_url添加到Kong中之后,我们测试从1到2000个并发连接的测试。
两分钟以上的117,185个请求,平均延迟为10ms,每秒976个请求,或者每天约84,373,200个请求通过Kong返回,只有一个超时。
Kong使用方式
- 一种应用通过携带Host头部来增加API应用。
- 另一种是通过不同的uri来提供API应用。
两种方式对OpenResty或者Nginx的使用方式都是基于动态增加upstream以及对upstream的DNS resolver来实现。
Kong部署
当前使用最新版本kong 0.9,我们部署在Centos 6.5 x64位系统上
$ wget https://bintray.com/mashape/kong-rpm-el6-0.9.x/rpm -O bintray-mashape-kong-rpm-el6-0.9.x.repo
$ mv bintray-mashape-kong-rpm-el6-0.9.x.repo /etc/yum.repos.d/
$ yum install kong
|
启动kong
$ kong start -c <path_to_config>
|
检查kong是不是正常启动了,默认不修改配置文件的情况下会报连接不上Postgresql,这里先忽略,继续装cassandra
正常启动的话会输出:[OK] Started
kong的监听端口:
8000: API请求的代理层。
8001: restful的配置管理API。
8443: 代理HTTPS
7946: 用于和其他Kong节点通讯,支持TCP/UDP流量
7373: 用于本地集群代理通讯
|
停止kong
$ kong stop
|
重新加载kong
$ kong reload
|
cassandra部署
java环境部署
这里就不演示安装了,yum也行,绿色版解压也行。java1.7 或者1.8都可以,注意cassandra3.0必须要jdk1.8版本才行。这里我们由于kong的支持版本是2.x,这里介绍2.x的安装。
yum源添加
$ vim /etc/yum.repos.d/datastax.repo
[datastax]
name = DataStax Repo for Apache Cassandra
baseurl = http://rpm.datastax.com/community
enabled = 1
gpgcheck = 0
$ yum search dsc
已加载插件:fastestmirror
Loading mirror speeds from cached hostfile
========================================================= N/S Matched: dsc ==========================================================
dsc1.1.noarch : Meta RPM for installation of the DataStax DSC platform
dsc12.noarch : Meta RPM for installation of the DataStax DSC platform
dsc20.noarch : Meta RPM for installation of the DataStax DSC platform
dsc21.noarch : Meta RPM for installation of the DataStax DSC platform
dsc22.noarch : Meta RPM for installation of the DataStax DSC platform
dsc30.noarch : Meta RPM for installation of the DataStax DSC platform
虽然有3.0,但是目前kong只支持2.2.x,这里我就安装2.2版本
$ yum install dsc22
|
启动cassandra
$ /etc/init.d/cassandra start
Starting Cassandra: OK
|
python2.7部署
cqlsh是cassandra的客户端查询工具
cqlsh客户的工具需要python2.7支持,centos6.x默认是python2.6版本,这里我新安装下python2.7
首先安装 python 工具需要的额外软件包 SSL,bz2,zlib
yum install -y zlib-devel bzip2-devel openssl-devel xz-libs wget
|
源码安装Python 2.7.x,当然你也可以偷懒yum安装,添加相应的yum就可以
$ wget http://www.python.org/ftp/python/2.7.8/Python-2.7.8.tar.xz
$ xz -d Python-2.7.8.tar.xz
$ tar -xvf Python-2.7.8.tar
$ cd Python-2.7.8
$ ./configure --prefix=/usr/local
$ make
$ make altinstall
|
检查 Python 版本并修复yum
$ python2.7 -V
Python 2.7.8
$ mv /usr/bin/python /usr/bin/python2.6.6
$ ln -s /usr/local/bin/python2.7 /usr/bin/python
$ which yum
/usr/bin/yum
#修改 yum中的python
将第一行 #!/usr/bin/python 改为 #!/usr/bin/python2.6
|
安装pip
$curl https://bootstrap.pypa.io/get-pip.py | python2.7 -
|
验证cassadnra
执行cqlsh客户端验证cassadnra安装
$ cqlsh
Traceback (most recent call last):
File "/usr/bin/cqlsh.py",line 160,in <module>
from cqlshlib import cql3handling,cqlhandling,pylexotron,sslhandling
ImportError: No module named cqlshlib
$ pip install cqlshlib
$ cqlsh
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 2.2.8 | CQL spec 3.3.1 | Native protocol v4]
Use HELP for help.
cqlsh> create schema testschema
... with replication = {'class':'SimpleStrategy','replication_factor':1};
cqlsh> describe keyspaces;
cqlsh> use testschema;
cqlsh:testschema> create table user (
... user_id varchar primary key,
... first varchar,
... last varchar,
... age int
... );
... user_id varchar primary key,
... age int
... );
cqlsh:testschema>
cqlsh:testschema> insert into user (user_id,first,last,age) values ('rfroncois','ronn','francois',20);
cqlsh:testschema> select * from user;
user_id | age | first | last
-----------+-----+-------+----------
rfroncois | 20 | ronn | francois
cqlsh:testschema>
|
Kong 配置
将数据库改为cassandra
$ cat /usr/local/kong/kong.conf
ssl_cert_key = /usr/local/kong/ssl/kong-default.key
ssl_cert_csr_default = /usr/local/kong/ssl/kong-default.csr
Nginx_acc_logs = /usr/local/kong/logs/access.log
anonymous_reports = true
lua_code_cache = on
serf_path = serf
Nginx_err_logs = /usr/local/kong/logs/error.log
log_level = notice
proxy_listen = 0.0.0.0:8000
ssl_cert = /usr/local/kong/ssl/kong-default.crt
cassandra_port = 9042
lua_ssl_verify_depth = 1
admin_listen = 0.0.0.0:8001
ssl_cert_key_default = /usr/local/kong/ssl/kong-default.key
ssl_cert_default = /usr/local/kong/ssl/kong-default.crt
serf_log = /usr/local/kong/logs/serf.log
dnsmasq_pid = /usr/local/kong/pids/dnsmasq.pid
proxy_listen_ssl = 0.0.0.0:8443
Nginx_worker_processes = auto
cassandra_contact_points = 127.0.0.1
proxy_ip = 0.0.0.0
cluster_profile = wan
pg_ssl = false
proxy_ssl_port = 8443
cassandra_timeout = 5000
pg_database = kong
lua_package_path = ?/init.lua;./kong/?.lua
cassandra_consistency = ONE
proxy_port = 8000
serf_node_id = /usr/local/kong/serf/serf.id
proxy_ssl_ip = 0.0.0.0
admin_ip = 0.0.0.0
kong_conf = /usr/local/kong/kong.conf
admin_port = 8001
prefix = /usr/local/kong
cluster_listen = 0.0.0.0:7946
cassandra_username = kong
pg_host = 127.0.0.1
pg_port = 5432
cluster_ttl_on_failure = 3600
dnsmasq_port = 8053
Nginx_daemon = on
serf_pid = /usr/local/kong/pids/serf.pid
cassandra_repl_strategy = SimpleStrategy
dnsmasq = true
Nginx_optimizations = true
pg_user = kong
pg_ssl_verify = false
cassandra_data_centers = dc1:2,dc2:3
cassandra_ssl_verify = false
ssl = true
database = cassandra
cassandra_repl_factor = 1
serf_event = /usr/local/kong/serf/serf_event.sh
cassandra_keyspace = kong
mem_cache_size = 128m
cassandra_ssl = false
cluster_listen_rpc = 127.0.0.1:7373
|
重启kong
$ kong restart
|
Kong使用
新增API
添加你的具体业务 API 服务到 Kong 中,Kong 通过 RESTful API 来管理具体的Kong 实例。具体请求如下,Kong 管理的 API 在8001 端口。请求配置如下:
$ curl -i -X POST \
--url http://localhost:8001/apis/ \
--data 'name=api-rest' \
--data 'upstream_url=http://api.yonghuivip.com/api/' \
--data 'request_host=api.yonghuivip.com'
|
- 请求的主机头中包含的DNS值。
- 请求的路径(URI)。
$ curl -i -X POST \
--url http://localhost:8001/apis/ \
-d 'name=mockbin' \
-d 'upstream_url=http://api.yonghuivip/' \
-d 'request_host=api.yonghuivip' \
-d 'request_path=/status'
```
这里首先看下DNS方式
|
$ curl -i -X GET \
–urlhttp://localhost:8000/\
–header ‘Host: api.yonghuivip’
当从浏览器执行请求时,您可能无法设置主机头。 因此,Kong还会检查一个名为X-Host-Override的头的请求,并像Host头一样设置它:
|
http://localhost:8000/\
–header ‘X-Host-Override: api.yonghuivip.com’
URI方式
|
$ curl -i -X GET \
–urlhttp://localhost:8000/status/200
> 通过kong代理请求的url 是 KONG_URL:PROXY_PORT/status/200 (http://localhost:8000/status/200)
> 我们配置的upstream_url 是 http://api.54im.com/
> 那我们最后的实际请求地址为 http://api.54im.com/status/200.
使用"strip_request_path"属性
|
$ curl -i -X PATCH \
–urlhttp://localhost:8001/apis/api\
-d ‘strip_request_path=true’ \
-d ‘request_path=/api’
可以看下使用strip_request_path后,请求路径的变化
request_path | strip_request_path | incoming request |upstream request
---|---|---|---
/api-rest| false | /some_path | not proxied
/api-rest | false | /api | /api
/api-rest | false | /api/some_path | /api/some_path
/api-rest | true | /some_path | not proxied
/api-rest | true | /api | /
/api-rest | true | /api/some_path | /some_path
我们这边就使用 Request URI方式测试
KONG 路由到业务的 API 使用: path URI 的方式请求 + 设置 strip_request_path 为 true
我现在拿这个api实验下
> http://api.54im.com/api/member/login?xxx=xxx&xxx=xxx
新增API
|
$ curl -i -X POST \
–urlhttp://localhost:8001/apis/\
-d ‘name=api’ \
-d ‘upstream_url=http://api.54im.com/‘ \
-d ‘request_host=api.54im.com’ \
-d ‘strip_request_path=true’ \
-d ‘request_path=/api’
返回
|
{
“upstream_url”: “http://api.54im.com/“,
“strip_request_path”: true,
“request_path”: “/api”,
“id”: “be9bb14d-f665-4d53-866c-1cd6e77bfc8b”,
“created_at”: 1476347080000,
“preserve_host”: false,
“name”: “api-rest”,
“request_host”: “api.54im.com”
}
我们来请求通过kong代理的业务的api
|
curl -i -X GET –url “http://localhost:8000/api/api/member/login?xxx=xxx&xxx=xxx“
> 这里说明下这个结构
>http://localhost:8000/api/api/member/login?
>http://localhost:8000/ 是kong提供的API代理层接口,提供给外界,当然你上层还是可以用负载均衡
>api 是上面新增接口中的 request_path
>api/member/login? 是我们业务具体的接口了
业务返回
```{
"code": 0,
"data": {
"xxx": "xxx",
"expires_in": "7200",
"refresh_token": "xxx",
"xxx": "xxx",
"uid": "21000"
},
"message": "OK",
"Now": 1476348465224
}
|
业务Nginx日志也可以看到该请求
10.10.1.2 - - [13/Oct/2016:16:33:10 +0800] "GET /api/member/login?v=2%2e0%2e1 HTTP/1.0" 500 184 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2" 127.0.0.1 0.005 -
|
Kong 插件管理
官网目前有这几类插件
Authentication 认证插件
- basic-authentication
- Key Authentication
- OAuth 2.0 Authentication
- HMAC Authentication
- JWT
- LDAP Authentication
Security 安全插件
- ACL
- CORS
- Dynamic SSL
- IP Restriction
- Bot Detection
Traffic Control 流控插件
- Rate Limiting
- Response Rate Limiting
- Request Size Limiting
Analytics & Monitoring 分析监控插件
Transformations 转换插件
- Request Transformer
- Response Transformer
- Correlation ID
Logging 日志插件
- TCP
- UDP
- HTTP
- File
- Syslog
- StatsD
- Loggly
Key Authentication 演示
[root@10-19-63-216:~]$ curl -i -X POST \
> --url http://localhost:8001/apis/api/plugins/ \
> --data 'name=key-auth'
HTTP/1.1 201 Created
Date: Thu,13 Oct 2016 09:01:55 GMT
Content-Type: application/json; charset=utf-8
transfer-encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/0.9.3
|
返回
{
"api_id": "be9bb14d-f665-4d53-866c-1cd6e77bfc8b",
"id": "9018a2c9-f532-4ea0-96aa-a7165181d8fe",
"created_at": 1476349315000,
"enabled": true,
"name": "key-auth",
"config": {
"key_names": [
"apikey"
],
"hide_credentials": false
}
}
|
我们同样请求之前那个接口看下
$ curl -i -X GET --url "http://localhost:8000/api/api/member/login?xxx=xxx&xxx=xxx"
HTTP/1.1 401 Unauthorized
Date: Thu,13 Oct 2016 09:03:17 GMT
Content-Type: application/json; charset=utf-8
transfer-encoding: chunked
Connection: keep-alive
WWW-Authenticate: Key realm="kong"
Server: kong/0.9.3
{"message":"No API key found in headers or querystring"}
|
那现在要认证了,我该如何访问接口呢,别急,继续往下
添加Consumers消费者
现在已经配置了 key-auth 插件,还需要添加 consumer 到 API,才能继续通过 Kong 代理请求。Consumer 在调用API时,与单个用户请求关联,能被用来跟踪、访问管理等等。
建立一个用户名称为Ivon 的 consumer,下面请求命令成功之后,Kong 还会为Jason 用户建立一个唯一的 custom_id。
$ curl -i -X POST \
--url http://localhost:8001/consumers/ \
--data "username=Jason"
|
为消费者Ivon提供密钥凭据
curl -i -X POST \
--url http://localhost:8001/consumers/Ivon/key-auth/ \
--data 'key=18b4ccb1a20076813c208d8e8a281a94'
|