本文是《 京东商品详情页服务闭环实践 》中未公开的一些细节,是15年内部培训的PPT,目前的内容也不过时,还适用现有系统架构设计。PPT下载地址: https://pan.baidu.com/s/1K-Djkf6IFZ7qSEIlNqYPAw 。
架构
单品页依赖服务众多,分布在各个部门。问题:
服务质量没有监控数据
出现问题不能及时降级
接口调用分散化
域名重复解析,没有长连接的优势
设计上无状态
使用nginx+lua+tomcat7架构
充分利用localcache(proxycache or shared_dict orjava guava cache)
使用localtwemproxy做redis分片,且缓存分离(重要业务与其他业务分离)
分离线程池,核心业务与非核心业务分离,且有线程池监控和开关
异步化更新
Redis集群使用主从架构
使用unixdomain socket减少连接数
使用keepalive长连接
考虑好开关
缓存时间、是否调用后端服务、托底(托底恢复采用指数/随机数恢复机制)
使用localtwemproxy做redis分片,且缓存分离(重要业务与其他业务分离)Redis集群使用集中式主从架构/ 考虑复制缓冲区大小
考虑使用unix domain socket/ 套接字放内存文件系统
考虑使用HashTag
Redis考虑缓存驱逐策略:maxmemory-policy allkeys-lru maxmemory-samples 10
使用长连接,并限制长连接数量
设置超时
使用内存文件系统进行 Nginx Proxy Cache
注意响应头对cache时间的影响
Parameters of caching can also beset directly in the response header. This has higher priority than setting ofcaching time using the directive. •The“X-Accel-Expires” header field sets caching time of a response in seconds. Thezero value disables caching for a response. If the value starts with the @ prefix,it sets an absolute time in seconds since Epoch, up to which the response maybe cached.•Ifthe header does not include the “X-Accel-Expires” field, parameters of cachingmay be set in the header fields “Expires” or “Cache-Control”.•Ifthe header includes the “Set-Cookie” field, such a response will not be cached.•Ifthe header includes the “Vary” field with the special value “*”,such a response will not be cached (1.7.7). If the header includes the “Vary”field with another value, such a response will be cached taking into accountthe corresponding request header fields (1.7.7).
数据有问题不要缓存
proxy_pass时使用Local DNS解析
可能解析到多个server(nslookup),会自动next upstream
Nginx plus支持upstream的动态解析
Nginx Gzip
根据自己需求设置gzip_comp_level、gzip_min_length、gzip_types
upstream检查
upstream策略 ip_hash
upstream策略 hash key [consistent]
consistent_key是根据流量负载动态计算的,如根据ip计算:
local newval, err = ip_log:incr(ip, 1) local toDelay = false -- 单IP恶意请求 分流到固定机组 if newval > 50 then toDelay = true ngx_var.consistent_key = ngx_var.consistent_key .. '_' .. newval --要在set_uri前执行,否则执行不到 end
限定请求头和请求体大小,在proxy pass到后端服务时不传输请求头和请求体,减少网络交互。
limit request
limit connection / limit rate
ip白名单/黑名单
user-agent白名单/黑名单
Token限流
漏桶算法令牌桶算法(JavaGuava rate limit)
Delay限速
参考 聊聊高并发系统之限流特技-1 、 聊聊高并发系统之限流特技-2 。
使用共享字典做local cache
请求时使用method参数表示请求哪个服务
数据过滤逻辑前置,不合法直接403(防止XSS)
封装调用逻辑,参数顺序等固定,提升缓存命中率
通过Nginx子请求(ngx.location.capture_multi)进行合并
只对原子接口进行Cache
通过一层代理重试或者记录UMP日志
记录日志还可以通过
异步非阻塞事件模型
从Servlet3开始支持异步模型,Tomcat7/Jetty8开始支持,相同的概念是Jetty6的Continuations。我们可以把处理过程分解为一个个的事件。
通过这种将请求划分为事件方式我们可以进行更多的控制。如,我们可以为不同的业务再建立不同的线程池进行控制:
即我们只依赖tomcat线程池进行请求的解析,对于请求的处理我们交给我们自己的线程池去完成;这样tomcat线程池就不是我们的瓶颈,造成现在无法优化的状况。
通过使用这种异步化事件模型,我们可以提高整体的吞吐量,不让慢速的A业务处理影响到其他业务处理。慢的还是慢,但是不影响其他的业务。
通过这种将请求划分为事件方式我们可以进行更多的控制。如,我们可以为不同的业务再建立不同的线程池进行控制:
start.sh
export JAVA_OPTS="-Djava.library.path=/usr/local/lib -server -XX:-UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:MaxDirectMemorySize=512m -Xss256k -XX:NewRatio=1 -XX:SurvivorRatio=6 -Xms16384m -Xms16384m -XX:MaxPermSize=256m -Djava.awt.headless=true -Dsun.net.client.defaultConnectTimeout=60000 -Dsun.net.client.defaultReadTimeout=60000 -Djmagick.systemclassloader=no -Dnetworkaddress.cache.ttl=300 -Dsun.net.inetaddr.ttl=300 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$CATALINA_BASE/logs -XX:ErrorFile=$CATALINA_BASE/logs/java_error_%p.log"
-XX:+UseConcMarkSweepGC 表示使用CMS
-XX:+CMSParallelRemarkEnabled 表示并行remark
-XX:+UseCMSCompactAtFullCollection 表示在FGC之后进行压缩,因为CMS默认不压缩空间的。
-XX:CMSInitiatingOccupancyFraction=80 设置阀值为80%,默认为68%。
-XX:SoftRefLRUPolicyMSPerMBsoftly reachable objects will remain alive for some amount of time after thelast time they were referenced. The default value is one second of lifetime perfree megabyte in the heap
-XX:NewRatio年轻代(包括Eden和两个Survivor区)与年老代的比值(不包括持久代)
-XX:SurvivorRatio Eden区与Survivor区的大小比值
server.xml
<Connector port="1601" asyncTimeout="10000" acceptCount="10240" maxConnections="10240" acceptorThreadCount="1" minSpareThreads="5" maxThreads="5" redirectPort="8443" processorCache="1024" URIEncoding="UTF-8" protocol="org.apache.coyote.http11.Http11NioProtocol" enableLookups="false"/>
以Tomcat 6为例,其Connector有几个关键配置:
BIO实现:
acceptCount:在超过最大连接数时,可接受的排队数量;超过这个值就直接拒绝连接;默认100;
maxThreads:tomcat可创建的最大线程数,没线程处理一个请求,它决定了tomcat最大线程阀值;默认200;
minSpareThreads:最小备用线程数,即tomcat一启动就创建的线程数;默认25;(使用Executor时配置)
maxQueueSize:最大备用线程数,一旦创建的线程超过这个值tomcat就会关闭不活动的线程;默认Integer.MAX_VALUE;(使用Executor时配置)
NIO实现(继承如上的配置):
acceptorThreadCount:接受连接的线程数;默认1,可以根据CPU核数调整;如果没有问题默认1个即可,基本不需要改;
pollerThreadCount:运行选择事件的线程个数;默认每核一个;
processorCache:协议处理器缓存Http11NioProcessor对象的个数,目的是提高性能,默认200,建议其值接近maxThreads;
对于tomcat7的相关配置可以参考官网http://tomcat.apache.org/tomcat-7.0-doc/config/http.html;核心差不多。
Java servlet3
线程池并发执行任务获取数据
异步更新缓存
local cache guava
批量接口时,对单个数据进行缓存;首先查询单个缓存,然后对miss数据进行批量获取,最后合并为结果
域名分区:客户端同域连接限制,进行域名分区:c.3.cn c1.3.cn c2.3.cn
充分使用CPU,比如绑定CPU核数
考虑减少连接数
考虑使用内存文件系统
考虑大内存或企业级SSD
全部使用弹性云
完。PPT下载地址: https://pan.baidu.com/s/1K-Djkf6IFZ7qSEIlNqYPAw 。
======广告======
作者:张开涛著
广告
购买
作者:京东商城基础架构部
广告
购买
作者:吕科等
广告
购买