移动网关最佳实践(tars)-后台
- tars微服务配置相关
- API限流
- API熔断
- API参数校验
- API签名
- API防重放
- APIMock测试
- API缓存
- 网关文件上传可能存在的风险与建议
- 重要优化建议升级
- 建议合理利用先悉告警及报表功能
- 网关网络问题相关
tars微服务配置相关
服务tars模板
说明与建议
tars.default和tars.defaultCoro为tars所有微服务可以引用的模板配置文件,前者默认不开协程,后者默认开协程。
同时服务即使引用了模板配置文件,也可以通过服务自身的私有模板配置来覆盖某些参数配置。
TMF下面的cpp编写的网关微服务建议全都选择tars.defaultCoro,提高并发处理性能。
查看与修改
查看单一服务某个节点的配置
tars控制台--->服务管理(定位到某个服务)--->"编辑"--->查看“*模板”配置内容--->取消 下图为查看Mazu服务用到的tars模板 如果想修改,则在模板对应下拉框选中需要修改的模板,然后单击"确定",最后重启对应节点即可
数据库查看所有服务节点用到的模板
use db_tars; select application,server_name,node_name,template_name,present_state from t_server_conf where application='TMF' and server_type='tars_cpp'; +-------------+--------------------------+-------------+--------------------+---------------+ | application | server_name | node_name | template_name | present_state | +-------------+--------------------------+-------------+--------------------+---------------+ | TMF | Mazu | 10.0.128.42 | tars.defaultCoro | active | | TMF | Mazu | 10.0.128.34 | tars.defaultCoro | active | ...
查看哪些服务节点没有启用协程模板
use db_tars; select application,server_name,node_name,template_name,present_state from t_server_conf where application='TMF' and template_name!='tars.defaultCoro' and server_type='tars_cpp'; ...
服务开启协程占用最大内存
说明与建议
该服务如果用到的是tars.defaultCoro模板,则默认是开启协程。协程的默认数量配置如下
#打开协程 opencoroutine=1 #协程内存大小 coroutinememsize=128M #协程栈大小 单位字节 coroutinestack=131072
coroutinememsize越大,能够最大开启的协程数量越多,瞬时并发处理能力越高
大部分服务建议使用tars.defaultCoro模板,然后采用默认设置即可
Mazu、SashimiServer、DRedisProxyServer服务建议将协程最大内存大小调整为1G或2G,提高网关并发处理能力
查看与修改
可以通过以下方法,查看/修改某服务对应节点的的私有模板,然后重启对应节点
tars控制台--->服务管理(定位到某个服务)--->"编辑" ---这里看到模板如果是使用了tars.defaultCoro,则默认开启协程 ---如果想修改定位到"私有模板",在其最后输入以下内容,然后点击“确定”保存,最后重启该节点即可 <tars> <application> <server> #打开协程 opencoroutine=1 #协程内存大小 coroutinememsize=1024M #协程栈大小 coroutinestack=131072 </server> </application> </tars>
- 一般通过修改coroutinememsize的大小,来修改最大协程内存即可
Servant处理线程数
说明与建议
- 每个微服务的每个Servant对应着1个监听端口,这里的处理线程数指的是该服务的该监听端口对应开启多少个并发处理线程
- 此线程数,默认为5,可根据实际情况适当调大,提高并发性能(前提是cpu资源充足)
- 本身已经开启了协程,此参数建议保持默认值5即可
查看与修改
tars控制台
tars控制台--->服务管理(定位到某个服务)--->"管理Servant"--->找到对应的Servant(或者端口)
下图为查看Mazu服务10.0.128.42节点 tcp端口30014对应的处理线程数
- 如果要修改,则点击上图中对应Servant后面的“编辑” 进行针对性的修改,然后确定,然后重启对应节点即可
Servant最大链接数
说明与建议
- 每个Servant对应一个监听端口,最大连接数为此监听端口可以保持的最大连接数量,默认200000,可根据实际情况适当调大提高并发性能(前提是内存资源充足)
- 建议维持默认值200000即可
查看与修改
Servant队列最大长度
说明与建议
- 最大队列长度 每个Servant对应的最大未处理请求队列长度 默认10000,此参数一般无需调整,因为只要业务线程处理及时,队列不会堆积。
查看与修改
Servant队列超时时间
说明与建议
- 请求到达Servant对应端口后,超时时间,默认60000ms也就是1分钟
- 建议维持默认值1分钟
查看与修改
API限流
说明与建议
- TMF网关当前限流是指通过控制单位时间内请求放行数量,来避免流量突发导致客户某个服务挂掉的情况
- 时间粒度为秒,也就是控制每秒放行请求数量
- 控制的业务范围粒度为API级别,也就是针对每个API控制每秒放行的数量
- 建议针对重要业务对应的API都开启限流,避免流量异常爆发,导致后端客户服务挂掉
- 建议升级部署最新的限流服务
关于旧限流存在的一些问题说明
这里的旧限流是指SashimiServer服务调用限流服务为FreqLimitServer,查看SashimiServer的FreqLimitApi.conf配置文件
如果FreqLimitServant=TMF.FreqLimitServer.FreqLimitObj,则为旧限流服务
如果FreqLimitServant=TMF.LimitFuseServer.LimitFuseObj,则为新限流服务
老的限流服务是不是严格精准的
简单来说就是如果1s流量超过阀值,会出现先全部放过,再全部不放过一段时间的情况,但整体上看是1s平均放过了多少个请求,第1秒过来的请求当前会全部放过(还没有触发过限流)
累计放过的数量然后检查这些放过的数量是否达到了配置的限流阀值,如果达到阀值,FreqLimitServer会根据通过的记录数和阀值数计算需要限流的时间(比如说1s内发了100笔请求,但阀值配置的是1,可能就要限制90秒) ,在这个需要限流的时间内,过来的请求全部拒绝
老的限流是不支持按照多中心分摊比例的方式的
查看与修改
开启限流
限流值配置建议(对应API每秒最大放行数量)
这个要根据客户自己服务的实际情况来配置
比如客户某个API对应的对应峰值QPS为1000(1s处理1000个请求),那这个限流阀值可以配置为1000或者适当减少,比如900、800
核心业务对应API建议客户对自己的业务真实压测,结合实际的极限处理QPS做合理的设置
比如压测后发现API极限为最多1秒处理1000个请求,那限流值一般就要适当减少,比如配置为900,800
API熔断
说明与建议
熔断是某个API如果连续出错(返回码异常5xx、超时等)达到一定次数,则会在一定时间内(尚未到达配置的熔断恢复时间间隔)自动触发该API的熔断(请求达到网关直接拒绝,不会再流转到客户后端服务器)
达到熔断恢复时间间隔,则会尝试发送发送少量请求(一般为1笔),检查是否成功
- 如果还是出错,则继续触发熔断。一定时间内(尚未到达配置的熔断恢复时间间隔)请求达到网关直接拒绝,不会再流转到客户后端服务器
- 如果成功则关闭熔断状态,继续根据连续出错次数再次自动判断是否需要触发熔断
- API熔断开关关闭,则不会触发API的熔断
- 打开后初始化状态为Close,连续失败(超时|返回码5xx)达到阀值,状态变为Open(一定时间内拒绝所有请求,然后状态变为HalfOpen)
- 状态为HalfOpen,放过1个请求,如果成功则状态变为Close,如果失败则状态重新变为Open
建议对核心业务API开启熔断机制,在客户核心业务不堪压力的时候给予一定的自恢复时间,避免出现高并发导致客户核心业务挂掉的情况
查看与修改
配置API的熔断
阀值就是连续出错累计次数,达到配置的值则自动触发熔断,这个要根据客户可以忍受的实际情况来配置
比如改API实际QPS为每秒1000个,可以接受连续失败/超时100次(已经连续失败请求超过1/10),则认为不可接受,大概率对应后端服务出现了问题,那么此值可以配置为100
恢复时间间隔单位为秒,触发熔断后则在配置时间内,直接拒绝请求,建议60s左右
API参数校验
说明与建议
当前网关可以对API调用中的参数做统一校验,在网关侧提前检验请求合法性,过滤一些无效的请求
- 比如url参数校验(必须传入某个值,否则为请求非法直接拒绝)
- 比如对某个参数做大小校验,不能传入大于某个值、对某个参数不显示指定则传入默认值等)
- 传入一些默认参数,提高开发效率
建议根据实际情况合理配置API的参数校验功能
查看与修改
配置API参数校验规则
- 参数位置支持query、body、header
- 参数类型支持string、int、long、float、double、boolean
- 支持必传校验(不传则请求非法,直接拒绝请求)
- 可对参数指定默认值(对于那些非必传有效)
- 最好给予一定人性化的描述配置
- 可以点击"编辑更多"为参数配置更多的校验规则,针对不同值类型有不同的配置,比如string可以配置最大长度,配置正则表达式校验,对于int可以配置最大最小值等
相关的错误码
- 1014 require字段没有找到,配置为必传,但是请求没有传入该参数
- 1015 参数检查,从body获取表单数据失败(k1=v1&k2=v2格式),一般为格式不合法
- 1016 不支持的参数位置,配置的参数位置不是query、body、header
- 1017 require必传字段找到,但是为空
- 1018 配置有枚举值排列,但传入的值不为其中一个,非法请求
- 1019 正则表达式不匹配,没有配置特殊的正则匹配,则是使用默认的类型匹配
- 1020 字符串长度过长
- 1021 bool值校验失败,传入的值不是"true" 也不是"false"
- 1022 数值超过配置的最大值
- 1023 数值小于配置的最小值
API签名
说明与建议
- 网关提供对API的请求进行签名计算,然后将hash值传与客户服务,客户服务可根据对应key重新hash计算,来实现签名校验,确保请求来自合法的客户端,中间也没有被篡改,提高安全性
- 建议重要业务对应API都开启签名校验功能
签名校验的大致流程
API开启签名校验,会生成随机密码,网关和客户服务使用次数同样的随机密码
App的请求到了网关,网关会用上面的密码对url参数(url?后面内容)和内容进行hash,默认用的是HMAC_EH_MD5,完成加签步骤
tmf会在参数里面先增加 tmf_nonce,tmf_timestamp,tmf_appid,tmf_signMethod几个值
tmf_nonce = xx随机数 tmf_timestamp = xx时间戳 tmf_appid = xxapiname tmf_signMethod = HMAC-MD5 tmf_signVer = 1
对url参数key按照字母序升序排序,拼接参数串,最后加上body内容得到字符串 strToBeSign,其中会对参数key和value做urlencode
strToBeSign="parma1=v1&parma2=v2&parma3=v3&body"
HMAC-EH_MD5(secert, strToBeSign)得到签名后的内容 signStr
signStr = HMAC-EH_MD5(secert, strToBeSign)
urlencode(Base64(signStr)) 后得到最终的签名串,这个会传给客户后端服务
对应的key为tmf_sign,这个也会添加到url参数串中
tmf_sign = urlencode(Base64(signStr))
客户服务端收到请求后,需要用HMAC_EH_MD5算法、密码为API配置的签名密码,参照上面的模式重新计算hash值,跟参数里面的tmf_sign进行比较,相等则签名校验成功,否则校验失败。
收到的请求url假设为: xxxurl?param1=v1¶m2=v2...
参数里面包含: tmf_sign=urlencode(Base64(signStr)) 上面tmf根据参数和body用密码hash出来的值 客户服务需要做的事情有以下几个步骤:建议对参数中的时间戳tmf_timestamp进行时间有效性校验,超过一定时间建议直接失败
去掉参数中的tmf_sign=xxx参数对,再拼接body strToBeSign="parma1=v1&parma2=v2&parma3=v3&body"
hmac进行hash运算
signStr = HMAC-EH_MD5(secert, strToBeSign)
得到客户侧的签名值
customer_sign = urlencode(Base64(signStr))
比较customer_sign和参数的tmf_sign值,相等则为校验成功,否则校验失败
param1,param2为url?后面的参数列表按key的字母序升序排序的结果,参数间用&符号链接 body是post时请求body内容,没有时留空,&符号保留
查看与修改
如何打开签名校验
API防重放
说明与建议
- 重放攻击就是把您的请求原封不动地再发送一次,两次...n次,防重放就是采取一定的安全校验机制避免同一个请求重复发送多次
- 网关提供API防重放的能力,建议针对核心业务API开启防重放功能
防重放原理介绍
同一个guid,对应的某一笔请求需要由客户端生成一个足够随机的nonce值,再加上CSashimi.seqNo
利用guid、nonce值、seqno按照一定规则生成一个key
此key在一定时间内不能重复发送2次或者2次以上的请求,否则认为是重放请求
具体时间参考SashimiServer.conf配置文件 对应配置项为iAntiReplayExpireTime 单位毫秒 建议保持默认值即可
查看与修改
打开防重放功能
APIMock测试
说明与建议
APIMock概念
- 对从移动端到移动网关服务的请求访问的返回进行Mock,提供待定的响应结果,以保证开发效率
- 主要应用场景是API客户服务端功能没有开发完毕,但是客户端(App/h5/小程序)相应功能已经开发完成,客户端想尽快启动联调测试,此时可以开启API的Mock测试,按照协定好的协议利用Mock功能模拟返回服务端的回包,提前进行联调测试,尽早发现问题,保证开发效率
- 建议合理利用该功能,提高开发效率
查看与修改
开启APIMock功能
验证Mock功能是否能够正常运转
API缓存
说明与建议
API缓存概念
- 首次API请求得到应答后,将应答结果缓存起来,一段时间内接下来的请求则直接用缓存结果进行应答,从而降低某些API后端客户服务器的压力,同时提高并发处理效率
应用场景
- 对于一些短时间应答结果不会变化的API,可以开启此缓存功能,降低后端压力,提高并发处理效率
- 建议针对以上情景的API开启缓存功能,提高处理效率
缓存位置
目前是按照APIID和配置的缓存来源按照一定规则组合为缓存key,将首次应答结果保存到redis中
查看与修改
正确配置API缓存
- 缓存来源支持header、query、cookie中的某个key的内容,上图配置来源为header中的city内容,假设首次调用city为guangzhou,则应答结果缓存后,后面只要请求header中city为guangzhou,则不会再发送请求到客户服务器,而是直接用缓存中的结果进行缓存
- 缓存时间单位为秒,上图中首次请求缓存后120秒内都不会再发请求到后端服务,而是直接用首次缓存结果进行应答
网关文件上传可能存在的风险与建议
网关提供文件上传服务,但不建议高频使用
因为流量经过TMF,如果频率很高,或者大文件很多,则有可能将带宽吃光,影响TMF网关、推送正常运转
文件上传服务属于IO操作耗时较大的业务,同时有大量文件上传,也会导致网关运行性能下降,甚至拖死网关
- 如果客户确实没有办法,有大量的并发文件上传,请确保SashimiServer的版本>=v_2.0.4_pre_20220402_0001,这个版本SashimiServer调用后端是异步RPC的方式,所以会适当缓解并发文件上传耗时操作对网关的冲击
重要优化建议升级
- 建议升级部署网关弱依赖redis功能,即使redis组件短暂异常,也可最大限度确保不影响网关API转发
- 建议升级部署网关限流优化功能,提供更好更精准的分布式限流体验
- 建议升级部署网关弱依赖mysql功能,即使tmfgateway实例短暂异常,也可最大限度确保不影响网关API转发
- 建议升级部署SashimiServer异步RPC优化功能,提高网关高并发处理能力
- 建议升级HTTPGoServer客户端耗时统计功能,可以更方便地监控API调用耗时情况
- 建议升级全链路日志跟踪功能,可以提高问题定位效率
建议合理利用先悉告警及报表功能
- 可尽早发现一些业务处理耗时告警,出现后可针对性的排查对应API的处理情况,避免带来更坏的影响
网关网络问题相关
IPv6相关
基本流程
TMF IPv6 环境依赖
1. 具备同时支持IPv4和IPv6的域名(即域名要有A记录还有AAAA记录)
2. LB同时具备IPv4 和 IPv6 转发能力
3. 网关服务器需绑定可路由的ipv6地址和绑定ipv4地址,以便同时提供IPv4 和IPv6 双栈服务
网关核心端口及配置相关
网关提供了2个端口 30014(tcp)、30013(http),前端LB设备需要确保指向了正确的地址
同时一般tcp为4层,http为7层。
如果前段部署有waf设备,则部署要求 30014 tcp 端口流量不经过 WAF(30013 端口流量可以经过 WAF),否则 30014 tcp 端口不通。无法提供自有通道推送功能
安卓端使用 tcp 通道进行请求,API 返回的数据过大,超过了 1M 的限制,则会返回50错误码
这里是一种保护机制,tcp 通道,如果包体过大,会阻塞连接上的其他请求的收发
建议客户请求数据量比较大的 API 时,在终端指定请求使用 HTTP 协议请求 API,HTTP 协议使用短连接方式进行请求,每次发起都是一次独立请求,不阻塞其他请求
网关检查工具
- 强烈建议部署网关网络检查工具 gatewaycheck,可检测网关相关大部分问题
说明:单击网关检查工具,即可下载。
./gatewaychecK -c TMFConfigurations_test.java_test -f TMFConfigurations_test.java_test
2022/08/15 16:41:22 &cmd.GwConf{Url:"http://127.0.0.1:30013", TcpHost:"127.0.0.1", TcpPort:"30014", HttpHost:"127.0.0.1", HttpPort:"30013", UploadUrl:"http://127.0.0.1:30013", Pid:8903}
2022/08/15 16:41:25 1. ping 127.0.0.1(tcp) success
2022/08/15 16:41:25 2. telnet 127.0.0.1:30014(tcp) success
2022/08/15 16:41:28 3. ping 127.0.0.1(http) success
2022/08/15 16:41:28 4. telnet 127.0.0.1:30013(http) success
2022/08/15 16:41:28 5. tcp to 127.0.0.1:30014(tcp) success, retCode=0
2022/08/15 16:41:28 6. curl http://127.0.0.1:30013(http) success
2022/08/15 16:41:28 7. SessionKey (tcp) success, sessionKey=ptWs33iykKSNzdr4|sessionId=MGJmZWMyOGY5NjAxNDM0ZTI1MmVjOTU5OTk0MmJkZGM2MTg4NjgzNTQ3NjMx
2022/08/15 16:41:28 8. Regist (tcp) success, guid=03000322081516412889016782359578
2022/08/15 16:41:28 9. Echo (tcp) success, retCode=0|dataRetCode=0
2022/08/15 16:41:29 10. SessionKey (http) success, sessionKey=ptWs33iykKSNzdr4|sessionId=NGI4ZTE4MjhkN2I2YzU1ODkyYTY5MmExNTYxYjgyOTE2MjE0NDI1MzMyNjA0
2022/08/15 16:41:29 11. Regist (http) success, guid=03000322081516412989016782359239
2022/08/15 16:41:29 12. Echo (http) success, retCode=0|dataRetCode=0
2022/08/15 16:41:29 13. File upload (http) success, retCode=1049|dataRetCode=0
客户端App真实IP透传
客户服务如果要获取客户端App的真实IP,请按照相关指导正确部署TOA,同时按照要求修改对应的负载(如F5)
当访问者(客户端)向TMF网关发起请求,访问请求通过负载均衡设备(比如F5)时,会将TCP数据包的源地址和目标地址均做修改,TMF网关获取到的原地址实际上为负载均衡设备的IP地址,不是真实的访问者IP地址。为解决该问题,需要通过
toa内核模块
实现服务端获取访问者真实IP。当访问请求通过负载均衡设备时,负载均衡设备向请求的TCP包(三次握手的最后一个ACK包)中的
TCP Option
字段中插入访问者的真实IP和端口信息,TMF网关通过toa内核模块
解析TCP Option中的IP和端口信息,以获取访问者的真实IP信息。TMF网关将请求转发给客户后端HTTP服务时,将获取到的访问者真实IP插入到相应的HTTP Header中,将访问者的真实IP透传到客户后端HTTP服务。
对接客户的HTTPS服务(api_url:https://xxx)
- 建议使用代理并正确配置HTTPGoServer.conf
- 如果没有代理,请确保升级了最新的HTTPGoServer