生产事故总结篇(2) 接口响应超时优化方案

1 查询类接口

一 mysql数据库查询超时问题

1 查询字段是否存在索引,索引是否失效

索引是个老生常谈的问题了, 需要特别注意下面几个点

唯一的值必须要建立唯一索引

比如订单号,售后单号,上门取件单号等必须要唯一的值,有助于数据准确

两个字段组成唯一的值必须要建立联合唯一索引

比如pps数据库表t_poroduct_supply 产品和商家供应商关系表, 正常来说supplier_id+product_id 肯定是唯一的值, 这里就要把这两个字段建立唯一索引, 避免产生脏数据, 查询效率也会变高, 需要注意一下联合索引的最左前缀, 只用product_id查询索引会失效的

同一个数据库下, 两张表同一个字段字符集不一样联查时索引会失效

这个问题曾经就遇到过,一张表是utf8格式, 另一张表是utf8mb4格式, 即使关联字段都是varchar类型, 索引也会失效

2 是否有分页?一次性返回数量是否过多导致堆内存溢出

问题描述:

在运费险白名单用户配置功能就遇到过这个问题,当时前端调用了两个接口, 一个是已分配用户列表, 一个是待分配用户列表(全部), 查询已分配用户列表时没有携带分页参数, 导致查询了全部已分配的用户数据(大概几十w条) , 直接后果就是pps服务器堆内存溢出,pps数据库cpu飙升 , 导致服务不可用

解决方案:

任何需要查询列表的接口, 必须都要使用分页, 前端可以采用默认查询第一页+ 支持精准搜索 方式展示,

拒绝一次性把所有列表数据拿到后在内存中做模糊匹配

3 数据库机器cpu是否正常?有没有可能其他慢SQL导致cpu飙升

这里主要看下执行时长, 平均返回行, 看是否存在执行时间过长,返回数据量过大的SQL产生, 具体页面在哪 怎样优化查询

4 数据库数据量大,根据某一状态查询变慢,可以默认加时间只查询最近一段周期数据

这个问题在上门取件列表根据未支付状态搜索遇到过, 表格数据总数大概一百万条数据, 用支付状态搜索时会SQL查询超时, 支付状态只存在几个值,加索引也没什么意义, 只能采用减少查询总量的方式去优化这部分查询, 只查最近一个月的数据, 大概有几万条, 查询效率就很高了

5 针对统计类数据,要是实时性不高,查询时间长,耗费cpu性能

缓存方案

在BMS系统首页有大量的统计数据, 这些统计数据查询的SQL一般在几百毫秒到几秒之间, ,因为这部分查询对实时性不高, 就加了接口切面级别的缓存, 避免存在相同条件的SQL短时间内重复请求数据库

统计表方案

针对于一些统计数据, 比如产品每日的维权率, 转化率等查询涉及到数据量很大时, 就可以将需要统计的数据存放在统计表中, 直接查询这张统计表就可以了

二 Redis超时问题

1 使用keys命令阻塞线程

因为redis是单线程执行的, 执行keys命令时底层是遍历所有的key匹配, 当一个库下面数据量很大时, 需要匹配的时间特别长, 而且会阻塞其他命令, 间接影响其他功能

问题代码:

下面代码是更新了店铺选款列表的配置后, 清空对应所有店铺下的缓存, 这里使用了keys模糊查询导致线程阻塞

优化代码:

因为店铺数量本来就不多,最多也就10多个店铺, 索性全部查询出来循环删除

056912158f73ce3d3ff38af36e8984c9.png

三 调用第三方接口查询超时问题

1 查询出的数据需要持久化

在使用上门取件功能时, 在调用下单接口会出现一定比例的接口超时, 超时原因是在调用第三方下单接口服务响应时长>5s, 成功响应后执行入库操作时, 因为超过了当前切面事务最大执行时间5s, 会抛出事务超时异常, 导致的问题是上门取件在服务商那边创建成功了, 但是在我们系统却找不到对应的订单, 后期用户也无法支付运费, 对平台造成一定的损失

问题代码:

可以看到在执行操作数据库操作时, 并没有针对出现的异常做重试, 导致需要新增的数据没有落库

优化代码:

抽离出操作DB的方法insertData(), 在执行抛出事务超时异常时,会启动一个子线程重试调用insertData(), 后续提示用户"下单成功,刷新页面", 避免用户重复点击造成重复下单

4ad46c74a17abc1084fe806dfd6e6f3c.png

2 查询出的数据不需要持久化

这种就是只针对于查询的需求了, 可能因为第三方接口不稳定导致接口响应慢, 在要求实时性不是很高时, 可以做一段时间的缓存, 减轻调用的qps

2 新增/更新类接口

1 批量操作代替循环操作

循环操作不管是DB还是OTS, 还有远程服务的调用, 每次循环都会产生的连接请求时间, 这都是一种资源的浪费, 优化方法就是请求数据在内存中整合好, 只调用一次持久化操作

2 大量数据分批操作

当需要新增或者更新几千条数据时, 一次性操作对数据库压力造成一定影响, 可以将需要操作的集合分片, 结合实际场景使用串行执行或者并行执行的方式

3 涉及复杂流程的单一操作可以并发执行

具体场景:

单独的新增业务复杂, 需要进行各种校验,不同状态执行不同流程, 这种情况下就不适合使用批量操作, 可以使用并发操作提高效率

代码案例:

例如填写售后单物流方法,一个方法执行时长大概100ms左右, 要是批量填写几百个串行操作耗时过长

优化代码:

使用callback多线程执行方式, 并行操作填写物流流程,大大提升了串行执行的效率, 并且将修改成功失败结果标识响应给用户

a3c2f8751b6da59f00aedf5f6e1a2875.png

3 调用远程接口响应超时

1 针对非核心逻辑可以使用异步方案处理降低总的接口调用时间

1 非核心逻辑 :

非核心逻辑可以理解为不需要和核心逻辑强绑定关系的逻辑, 可以不在一个事务里, 非核心逻辑的失败也不要影响核心逻辑的执行,

具体场景 :

1 例如下单扣减库存, 库存扣减(非核心逻辑)失败不要响应下单成功的结果

2 上门取件接单后给用户发送接单短信, 发短信(非核心逻辑)的失败不要影响取件单接单状态的变更

3 仓库收货错误商家原因处罚商家, 处罚商家(非核心逻辑)的失败不要影响仓库收货步骤

2 异步方案

消息队列:

消息队列是一种通知消息, 可以解除业务之间的耦合关系, 从接口调用的强耦合转为消息传递的松耦合, 上游不用关心下游成功与否, 都不影响主要流程执行, 一般作用在跨项目间业务的交互

案例1 : 下单扣减库存mq

下单时把对应的扣减库存参数传递个下游, 下游执行扣减库存逻辑, 不影响整个上游下单流程

案例2 : 仓库收货错误生成处罚给商家

仓库收货后, 把生成处罚相关参数传递给处罚模块, 处罚模块根据通知执行新增处罚流程,处罚生成与否, 不影响仓库收货流程

子线程执行 :

子线程也是一种优化方法耗时的一种方法, 核心逻辑执行完成后, 直接给客户端响应回去, 后续流程可以启动子线程继续执行, 这种是针对于实时性要求不高, 可以提升接口响应效率的一种手段

案例1 : 同步ES操作

更新库存接口中, 核心逻辑修改库存执行后, 启动一个子线程同步ES, 减少用户等待时间, 需要特别注意一下, 子线程内部一定要上报异常日志, 不然子线程内部报错后不能在loghub上看到

2 单独优化响应时长偏高的接口

有些接口业务很复杂, 调用了很多的远程调用, 偶尔就会不明原因的超时, 这时候可以去阿里云后台开一下接口整体执行时间, 看下到底是哪个接口执行耗时导致的

案例1 : 优化修改供货变更库存及库存状态逻辑

在整体调用链路中发现com.weidiango.pps.stock.impl.ProductSkuStockServiceImpl#batchAddSkuStockPlan接口时长占了总时长很大的比例, 在不影响整体业务流程的情况下, 保证这个接口入参,出参不变, 优化其中内部逻辑

问题代码:

主要逻辑是for循环内串行执行添加补货计划核心逻辑(修改库存, 修改库存状态, 上报操作记录), 这个流程在sku量不大的情况下执行时间还可以接受, 当sku数量>100个时, 耗时会>5s 导致超时

优化代码:

采用callback多线程优化方式, 并行执行更新补货计划逻辑, 因为更新的sku都归属于一个产品, 把更新供货状态和上报操作记录放在外层, 保证只需要执行一次即可, 从原来100个sku时长6s左右 优化到1s左右

3 涉及到多次调用不同的远程服务,可以通过串行改并行的方式调用,统一获取返回值

具体场景:

比如在下单时,

需要用到用户地址信息, 需要远程调用用户地址信息, 产品信息,

需要远程调用产品详情快照保存起来, 优惠卷信息,

需要调用查询最终用户需支付金额 等一系列的接口,

在分布式项目下, 各个模快信息都需要远程调用查询, 一个接口就算100ms, 涉及到的接口多起来总体下单时长也是很长的

解决方案 :

可以使用callback线程模式并行查询, 统一接收返回值做后续流程处理

高并发下解决方案:

上面说到的用户信息查询接口需要调用用户查询接口、积分查询接口 和 成长值查询接口,然后汇总数据统一返回。

那么,我们能不能把数据冗余一下,把用户信息、积分和成长值的数据统一存储到一个地方,比如:redis,存的数据结构就是用户信息查询接口所需要的内容。然后通过用户id,直接从redis中查询数据出来,不就OK了?

如果在高并发的场景下,为了提升接口性能,远程接口调用大概率会被去掉,而改成保存冗余数据的数据异构方案。

但需要注意的是,如果使用了数据异构方案,就可能会出现数据一致性问题。

用户信息、积分和成长值有更新的话,大部分情况下,会先更新到数据库,然后同步到redis。但这种跨库的操作,可能会导致两边数据不一致的情况产生。

4 避免在循环中调用远程方法,提供批量查询接口只调用一次

批量操作的这种思想不管是在前端调用后端接口, 后端远程接口调用, 操作DB, 操作OTS, 能使用批量执行尽量用批量执行, 除非接口层面不支持批量操作, 单针对于这种可以采用callback多线程方式优化

4 排查接口超时常用工具

1 调用耗时剖析

一个接口超时, 先入为主的必然是这个接口的调用路径, 上下游调用链路, 每个链路执行耗时情况, 具体原因具体分析

com.weidiango.api.pps.service.ItemTagLibraryService@selectTagByItemId接口为例可以看出该接口内部执行的耗时情况

2 资源饼图分析

这里可以看出底层储存执行的耗时情况, 如果是mysql或者redis 耗时占比很大, 就要到对应的数据库下面看下数据库的cpu情况和慢SQL情况

3 mysql实例的cpu和慢日志分析

主要关注在接口超时的时间范围内, 数据库cpu的波动和执行慢SQL的语句,

观察是因为超时接口的慢SQL导致cpu上升从而查询变慢,

还是其他的慢SQL执行导致cpu上升而影响了当前执行的接口耗时

4 Redis实例的cpu和慢日志分析

当执行一条耗时的redis命令时(例如keys), 可以看到cpu会显著升高, 慢日志中也会打印出这条命令, 当前执行的方法会一直阻塞执行这条命令等待redis执行结束, 共享当前redis实例的其他请求会因为redis线程池满从而把请求拒绝掉, 影响其他操作redis的业务执行

5 超时日志的比例与参数查看

可以通过loghub查询某个接口日志的总数与超时总数, 分析出大概的超时比例, 根据参数分析大概超时的原因

com.weidiango.reserve.svc.Impl.ReserveOrderServiceImpl#add 以这个接口为例

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第1部分概述 1 1 交易型系统设计的一些原则 2 1.1 高并发原则 3 1.1.1 无状态 3 1.1.2 拆分 3 1.1.3 服务化 4 1.1.4 消息队列 4 1.1.5 数据异构 6 1.1.6 缓存银弹 7 1.1.7 并发化 9 1.2 高可用原则 10 1.2.1 降级 10 1.2.2 限流 11 1.2.3 切流量 12 1.2.4 可回滚 12 1.3 业务设计原则 12 1.3.1 防重设计 13 1.3.2 幂等设计 13 1.3.3 流程可定义 13 1.3.4 状态与状态机 13 1.3.5 后台系统操作可反馈 14 1.3.6 后台系统审批化 14 1.3.7 文档和注释 14 1.3.8 备份 14 1.4 总结 14 第2部分高可用 17 2 负载均衡与反向代理 18 2.1 upstream配置 20 2.2 负载均衡算法 21 2.3 失败重试 23 2.4 健康检查 24 2.4.1 TCP心跳检查 24 2.4.2 HTTP心跳检查 25 2.5 其他配置 25 2.5.1 域名上游服务器 25 2.5.2 备份上游服务器 26 2.5.3 不可用上游服务器 26 2.6 长连接 26 2.7 HTTP反向代理示例 29 2.8 HTTP动态负载均衡 30 2.8.1 Consul+Consul-template 31 2.8.2 Consul+OpenResty 35 2.9 Nginx四层负载均衡 39 2.9.1 静态负载均衡 39 2.9.2 动态负载均衡 41 参考资料 42 3 隔离术 43 3.1 线程隔离 43 3.2 进程隔离 45 3.3 集群隔离 45 3.4 机房隔离 46 3.5 读写隔离 47 3.6 动静隔离 48 3.7 爬虫隔离 49 3.8 热点隔离 50 3.9 资源隔离 50 3.10 使用Hystrix实现隔离 51 3.10.1 Hystrix简介 51 3.10.2 隔离示例 52 3.11 基于Servlet 3实现请求隔离 56 3.11.1 请求解析和业务处理线程池分离 57 3.11.2 业务线程池隔离 58 3.11.3 业务线程池监控/运维/降级 58 3.11.4 如何使用Servlet 3异步化 59 3.11.5 一些Servlet 3异步化压测数据 64 4 限流详解 66 4.1 限流算法 67 4.1.1 令牌桶算法 67 4.1.2 漏桶算法 68 4.2 应用级限流 69 4.2.1 限流总并发/连接/请求数 69 4.2.2 限流总资源数 70 4.2.3 限流某个接口的总并发/请求数 70 4.2.4 限流某个接口的时间窗请求数 70 4.2.5 平滑限流某个接口的请求数 71 4.3 分布式限流 75 4.3.1 Redis+Lua实现 76 4.3.2 Nginx+Lua实现 77 4.4 接入层限流 78 4.4.1 ngx_http_limit_conn_module 78 4.4.2 ngx_http_limit_req_module 80 4.4.3 lua-resty-limit-traffic 88 4.5 节流 90 4.5.1 throttleFirst/throttleLast 90 4.5.2 throttleWithTimeout 91 参考资料 92 5 降级特技 93 5.1 降级预案 93 5.2 自动开关降级 95 5.2.1 超时降级 95 5.2.2 统计失败次数降级 95 5.2.3 故障降级 95 5.2.4 限流降级 95 5.3 人工开关降级 96 5.4 读服务降级 96 5.5 写服务降级 97 5.6 多级降级 98 5.7 配置中心 100 5.7.1 应用层API封装 100 5.7.2 配置文件实现开关配置 101 5.7.3 配置中心实现开关配置 102 5.8 使用Hystrix实现降级 106 5.9 使用Hystrix实现熔断 108 5.9.1 熔断机制实现 108 5.9.2 配置示例 112 5.9.3 采样统计 113 6 超时与重试机制 117 6.1 简介 117 6.2 代理层超时与重试 119 6.2.1 Nginx 119 6.2.2 Twemproxy 126 6.3 Web容器超时 127 6.4 中间件客户端超时与重试 127 6.5 数据库客户端超时 131 6.6 NoSQL客户端超时 134 6.7 业务超时 135 6.8 前端Ajax超时 135 6.9 总结 136 6.10 参考资料 137 7 回滚机制 139 7.1 事务回滚 139 7.2 代码库回滚 140 7.3 部署版本回滚 141 7.4 数据版本回滚 142 7.5 静态资源版本回滚 143 8 压测与预案 145 8.1 系统压测 145 8.1.1 线下压测 146 8.1.2 线上压测 146 8.2 系统优化和容灾 147 8.3 应急预案 148 第3部分高并发 153 9 应用级缓存 154 9.1 缓存简介 154 9.2 缓存命中率 155 9.3 缓存回收策略 155 9.3.1 基于空间 155 9.3.2 基于容量 155 9.3.3 基于时间 155 9.3.4 基于Java对象引用 156 9.3.5 回收算法 156 9.4 Java缓存类型 156 9.4.1 堆缓存 158 9.4.2 堆外缓存 162 9.4.3 磁盘缓存 162 9.4.4 分布式缓存 164 9.4.5 多级缓存 166 9.5 应用级缓存示例 167 9.5.1 多级缓存API封装 167 9.5.2 NULL Cache 170 9.5.3 强制获取最新数据 170 9.5.4 失败统计 171 9.5.5 延迟报警 171 9.6 缓存使用模式实践 172 9.6.1 Cache-Aside 173 9.6.2 Cache-As-SoR 174 9.6.3 Read-Through 174 9.6.4 Write-Through 176 9.6.5 Write-Behind 177 9.6.6 Copy Pattern 181 9.7 性能测试 181 9.8 参考资料 182 10 HTTP缓存 183 10.1 简介 183 10.2 HTTP缓存 184 10.2.1 Last-Modified 184 10.2.2 ETag 190 10.2.3 总结 192 10.3 HttpClient客户端缓存 192 10.3.1 主流程 195 10.3.2 清除无效缓存 195 10.3.3 查找缓存 196 10.3.4 缓存未命中 198 10.3.5 缓存命中 198 10.3.6 缓存内容陈旧需重新验证 202 10.3.7 缓存内容无效需重新执行请求 205 10.3.8 缓存响应 206 10.3.9 缓存头总结 207 10.4 Nginx HTTP缓存设置 208 10.4.1 expires 208 10.4.2 if-modified-since 209 10.4.3 nginx proxy_pass 209 10.5 Nginx代理层缓存 212 10.5.1 Nginx代理层缓存配置 212 10.5.2 清理缓存 215 10.6 一些经验 216 参考资料 217 11 多级缓存 218 11.1 多级缓存介绍 218 11.2 如何缓存数据 220 11.2.1 过期与不过期 220 11.2.2 维度化缓存与增量缓存 221 11.2.3 大Value缓存 221 11.2.4 热点缓存 221 11.3 分布式缓存与应用负载均衡 222 11.3.1 缓存分布式 222 11.3.2 应用负载均衡 222 11.4 热点数据与更新缓存 223 11.4.1 单机全量缓存+主从 223 11.4.2 分布式缓存+应用本地热点 224 11.5 更新缓存与原子性 225 11.6 缓存崩溃与快速修复 226 11.6.1 取模 226 11.6.2 一致性哈希 226 11.6.3 快速恢复 226 12 连接池线程池详解 227 12.1 数据库连接池 227 12.1.1 DBCP连接池配置 228 12.1.2 DBCP配置建议 233 12.1.3 数据库驱动超时实现 234 12.1.4 连接池使用的一些建议 235 12.2 HttpClient连接池 236 12.2.1 HttpClient 4.5.2配置 236 12.2.2 HttpClient连接池源码分析 240 12.2.3 HttpClient 4.2.3配置 241 12.2.4 问题示例 243 12.3 线程池 244 12.3.1 Java线程池 245 12.3.2 Tomcat线程池配置 248 13 异步并发实战 250 13.1 同步阻塞调用 251 13.2 异步Future 252 13.3 异步Callback 253 13.4 异步编排CompletableFuture 254 13.5 异步Web服务实现 257 13.6 请求缓存 259 13.7 请求合并 261 14 如何扩容 266 14.1 单体应用垂直扩容 267 14.2 单体应用水平扩容 267 14.3 应用拆分 268 14.4 数据库拆分 271 14.5 数据库分库分表示例 275 14.5.1 应用层还是中间件层 275 14.5.2 分库分表策略 277 14.5.3 使用sharding-jdbc分库分表 279 14.5.4 sharding-jdbc分库分表配置 279 14.5.5 使用sharding-jdbc读写分离 283 14.6 数据异构 284 14.6.1 查询维度异构 284 14.6.2 聚合数据异构 285 14.7 任务系统扩容 285 14.7.1 简单任务 285 14.7.2 分布式任务 287 14.7.3 Elastic-Job简介 287 14.7.4 Elastic-Job-Lite功能与架构 287 14.7.5 Elastic-Job-Lite示例 288 15 队列术 295 15.1 应用场景 295 15.2 缓冲队列 296 15.3 任务队列 297 15.4 消息队列 297 15.5 请求队列 299 15.6 数据总线队列 300 15.7 混合队列 301 15.8 其他队列 302 15.9 Disruptor+Redis队列 303 15.9.1 简介 303 15.9.2 XML配置 304 15.9.3 EventWorker 305 15.9.4 EventPublishThread 307 15.9.5 EventHandler 308 15.9.6 EventQueue 308 15.10 下单系统水平可扩展架构 311 15.10.1 下单服务 313 15.10.2 同步Worker 313 15.11 基于Canal实现数据异构 314 15.11.1 Mysql主从复制 315 15.11.2 Canal简介 316 15.11.3 Canal示例 318 第4部分案例 323 16 构建需求响应式亿级商品详情页 324 16.1 商品详情页是什么 324 16.2 商品详情页前端结构 325 16.3 我们的性能数据 327 16.4 单品页流量特点 327 16.5 单品页技术架构发展 327 16.5.1 架构1.0 328 16.5.2 架构2.0 328 16.5.3 架构3.0 330 16.6 详情页架构设计原则 332 16.6.1 数据闭环 332 16.6.2 数据维度化 333 16.6.3 拆分系统 334 16.6.4 Worker无状态化+任务化 334 16.6.5 异步化+并发化 335 16.6.6 多级缓存化 335 16.6.7 动态化 336 16.6.8 弹性化 336 16.6.9 降级开关 336 16.6.10 多机房多活 337 16.6.11 多种压测方案 338 16.7 遇到的一些坑和问题 339 16.7.1 SSD性能差 339 16.7.2 键值存储选型压测 340 16.7.3 数据量大时JIMDB同步不动 342 16.7.4 切换主从 342 16.7.5 分片配置 342 16.7.6 模板元数据存储HTML 342 16.7.7 库存接口访问量600w/分钟 343 16.7.8 微信接口调用量暴增 344 16.7.9 开启Nginx Proxy Cache性能不升反降 344 16.7.10 配送至读服务因依赖太多,响应时间偏慢 344 16.7.11 网络抖动时,返回502错误 346 16.7.12 机器流量太大 346 16.8 其他 347 17 京东商品详情页服务闭环实践 348 17.1 为什么需要统一服务 348 17.2 整体架构 349 17.3 一些架构思路和总结 350 17.3.1 两种读服务架构模式 351 17.3.2 本地缓存 352 17.3.3 多级缓存 353 17.3.4 统一入口/服务闭环 354 17.4 引入Nginx接入层 354 17.4.1 数据校验/过滤逻辑前置 354 17.4.2 缓存前置 355 17.4.3 业务逻辑前置 355 17.4.4 降级开关前置 355 17.4.5 AB测试 356 17.4.6 灰度发布/流量切换 356 17.4.7 监控服务质量 356 17.4.8 限流 356 17.5 前端业务逻辑后置 356 17.6 前端接口服务端聚合 357 17.7 服务隔离 359 18 使用OpenResty开发高性能Web应用 360 18.1 OpenResty简介 361 18.1.1 Nginx优点 361 18.1.2 Lua的优点 361 18.1.3 什么是ngx_lua 361 18.1.4 开发环境 362 18.1.5 OpenResty生态 362 18.1.6 场景 362 18.2 基于OpenResty的常用架构模式 363 18.2.1 负载均衡 363 18.2.2 单机闭环 364 18.2.3 分布式闭环 367 18.2.4 接入网关 368 18.2.5 核心接入Nginx功能 369 18.2.6 业务Nginx功能 369 18.2.7 Web应用 370 18.3 如何使用OpenResty开发Web应用 371 18.3.1 项目搭建 371 18.3.2 启停脚本 372 18.3.3 配置文件 372 18.3.4 nginx.conf配置文件 373 18.3.5 Nginx项目配置文件 373 18.3.6 业务代码 374 18.3.7 模板 374 18.3.8 公共Lua库 375 18.3.9 功能开发 375 18.4 基于OpenResty的常用功能总结 375 18.5 一些问题 376 19 应用数据静态化架构高性能单页Web应用 377 19.1 整体架构 378 19.1.1 CMS系统 379 19.1.2 前端展示系统 380 19.1.3 控制系统 380 19.2 数据和模板动态化 381 19.3 多版本机制 381 19.4 异常问题 382 20 使用OpenResty开发Web服务 383 20.1 架构 383 20.2 单DB架构 384 20.2.1 DB+Cache/数据库读写分离架构 384 20.2.2 OpenResty+Local Redis+Mysql集群架构 385 20.2.3 OpenResty+Redis集群+Mysql集群架构 386 20.3 实现 387 20.3.1 后台逻辑 388 20.3.2 前台逻辑 388 20.3.3 项目搭建 389 20.3.4 Redis+Twemproxy配置 389 20.3.5 Mysql+Atlas配置 390 20.3.6 Java+Tomcat安装 394 20.3.7 Java+Tomcat逻辑开发 395 20.3.8 Nginx+Lua逻辑开发 401 21 使用OpenResty开发商品详情页 405 21.1 技术选型 407 21.2 核心流程 408 21.3 项目搭建 408 21.4 数据存储实现 410 21.4.1 商品基本信息SSDB集群配置 410 21.4.2 商品介绍SSDB集群配置 413 21.4.3 其他信息Redis配置 417 21.4.4 集群测试 418 21.4.5 Twemproxy配置 419 21.5 动态服务实现 422 21.5.1 项目搭建 422 21.5.2 项目依赖 422 21.5.3 核心代码 423 21.5.4 基本信息服务 424 21.5.5 商品介绍服务 426 21.5.6 其他信息服务 426 21.5.7 辅助工具 427 21.5.8 web.xml配置 428 21.5.9 打WAR包 428 21.5.10 配置Tomcat 428 21.5.11 测试 429 21.5.12 Nginx配置 429 21.5.13 绑定hosts测试 430 21.6 前端展示实现 430 21.6.1 基础组件 430 21.6.2 商品介绍 432 21.6.4 前端展示 434 21.6.5 测试 442

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值