爱思乐电商项目常见问题(下)

你们这个项目有秒杀吗,怎么实现的?

所谓“秒杀”,就是网络卖家发布一些超低价格的商品,所有买家在同一时间网上抢购的一种销售方式。通俗一点讲就是网络商家为促销等目的组织的网上限时抢购活动。由于商品价格低廉,往往一上架就被抢购一空,有时只用一秒钟。

秒杀商品通常有两种限制:库存限制、时间限制。

需求:

(1)商家提交秒杀商品申请,录入秒杀商品数据,主要包括:商品标题、原价、秒杀价、商品图片、介绍等信息

(2)运营商审核秒杀申请

(3)秒杀频道首页列出秒杀商品(进行中的)点击秒杀商品图片跳转到秒杀商品详细页。

(4)商品详细页显示秒杀商品信息,点击立即抢购实现秒杀下单,下单时扣减库存。当库存为0 或不在活动期范围内时无法秒杀。

(5)秒杀下单成功,直接跳转到支付页面(微信扫码),支付成功,跳转到成功页,填写收货地址、电话、收件人等信息,完成订单。

(6)当用户秒杀下单 5 分钟内未支付,取消预订单,调用微信支付的关闭订单接口,恢复库存。

数据库表分析

Tb_seckill_goods 秒杀商品表

爱思乐电商项目常见问题(下)_第1张图片

Tb_seckill_order 秒杀订单表

爱思乐电商项目常见问题(下)_第2张图片

秒杀实现思路

  秒杀技术实现核心思想是运用缓存减少数据库瞬间的访问压力!读取商品详细信息时运用缓存,当用户点击抢购时减少 redis 中的库存数量,当库存数为 0 时或活动期结束时,同步到数据库。 产生的秒杀预订单也不会立刻写到数据库中,而是先写到缓存,当用户付款成功后再写入数据库。

你们这个项目用的什么数据库,数据库有多少张表?

项目使用 mysql 数据库,总共有 103 张表,其中商品表共计有 8 张。

项目部署做过吗,能不能部署?

做过,可以部署。

项目服务器:集群部署

数据库服务器:集群部署

Nginx 集群:负载均衡

单点登录怎么做的,用别人知道原理吗?

在分布式项目中实现 session 共享,完成分布式系统单点登录

3) Cookie 中共享 ticket

4) Redis 存储 session

分布式系统共享用户身份信息 session,必须先获取 ticket 票据,然后再根据票据信息获取 redis 中用户身份信息。

实现以上 2 点即可实现 session 共享。

爱思乐电商项目常见问题(下)_第3张图片

目前项目中使用的 springsecurity + cas 来实现的单点登录,cas 自动产生 ticket 票据信息,每次获取用户信息,cas 将会携带 ticket 信息获取用户身份信息。

支付做了吗,支付宝还是微信,实现说下?

微信支付

微信支付:

1) 调用微信支付下单接口

2) 返回支付地址,生成二维码

3) 扫描二维码即可完成支付

问题: 微信支付二维码是我们自己生成的,因此必须时刻监控微信支付二维码的状态,确保支付成功。


缓存及优化方面的面试问题

怎么提高 redis 缓存利用率?

1、从业务场景分析,预计会高频率用到的数据预先存放到 redis 中,

2、可以定时扫描命中率低的数据,可以直接从 redis 中清除。

怎么实现数据量大、 并发量高的搜索

创建 solr 索引库,数据量特别大时采用 solr 分布式集群

怎么分词

使用第三方的分词器 IKAnalyzer,会按照中国人用此习惯自动分词。

seo 怎么优化

使用 restful,或静态页这样能更好的被搜索引擎收录。

怎么加快访问速度

硬件上加大网络带宽、和服务器内存

代码的处理:静态页面、缓存、优化 sql、创建索引等方案

讲到 redis 缓存的时候说不清楚

1、 redis 中项目中的应用。

            1.主要应用在门户网站首页广告信息的缓存。因为门户网站访问量较大,将广告缓存到 redis 中,可以降低数据库访问压力,提高查询性能。

            2.应用在用户注册验证码缓存。利用 redis 设置过期时间,当超过指定时间后,redis 清理验证码,使过期的验证码无效。

            3.用在购物车模块,用户登陆系统后,添加的购物车数据需要保存到 redis 缓存中。

2、 技术角度分析:

        2.1 内存如果满了,采用 LRU 算法进行淘汰。

        2.2Redis 如何实现负载的?采用 Hash 槽来运算存储值,使用 CRC16 算法取模运算,来保证负载问题。

        2.3Redis 缓存穿透问题?将数据查询出来如果没有强制设置空值,并且设置过期时间,减少频繁查询数据库。

能讲下 redis 的具体使用场景吗?使用 redis 存储长期不改变的数据完全可以使用也看静态化,那么你们当时是为什么会使用 redis?

redis 在项目中应用:

        1.主要应用在门户网站首页广告信息的缓存。因为门户网站访问量较大,将广告缓存到 redis 中,可以降低数据库访问压力,提高查询性能。

        2.应用在用户注册验证码缓存。利用 redis 设置过期时间,当超过指定时间后,redis 清理验证码,使过期的验证码无效。

        3.用在购物车模块,用户登陆系统后,添加的购物车数据需要保存到 redis 缓存中。

使用 redis 主要是减少系统数据库访问压力。从缓存中查询数据,也提高了查询性能,挺高用户体验度。

redis 中对一个 key 进行自增或者自减操作,它是原子性的吗?

是原子性的。对于 Redis 而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,要么不执行。Redis 的操作之所以是原子性的,是因为 Redis 是单线程的。对 Redis 来说,执行 get、set 以及 eval 等 API,都是一个一个的任务,这些任务都会由Redis 的线程去负责执行,任务要么执行成功,要么执行失败,这就是 Redis 的命令是原子性的原因。Redis 本身提供的所有 API 都是原子操作,Redis 中的事务其实是要保证批量操作的原子性。

你们项目中使用到的数据库是什么?你有涉及到关于数据库到建库建表操作吗?数据库创建表的时候会有哪些考虑呢?

项目中使用的是 MySQL 数据库,数据库创建表时要考虑

a、大数据字段最好剥离出单独的表,以便影响性能

b、使用 varchar,代替 char,这是因为 varchar 会动态分配长度,char 指定为 20,即时你存储字符“1”,它依然是 20 的长度

c、给表建立主键,看到好多表没主键,这在查询和索引定义上将有一定的影响

d、避免表字段运行为 null,如果不知道添加什么值,建议设置默认值,特别 int 类型,比如默认值为 0,在索引查询上,效率立显。

e、建立索引,聚集索引则意味着数据的物理存储顺序,最好在唯一的,非空的字段上建立,其它索引也不是越多越好,索引在查询上优势显著,在频繁更新数据的字段上建立聚集索引,后果很严重,插入更新相当忙。

f、组合索引和单索引的建立,要考虑查询实际和具体模式

mysql 中哪些情况下可以使用索引,哪些情况不能使用索引?mysql 索引失效的情形有哪些?

使用索引:

a、 为了快速查找匹配 WHERE 条件中涉及到列。

b、 如果表有一个 multiple-column 索引,任何一个索引的最左前缀可以通过使用优化器来查找行

c、 当运行 joins 时,为了从其他表检索行。MySql 可以更有效的使用索引在多列上如果他们声明的类型和大小是一样的话。在这个环境下,VARCHAR 和 CHAR 是一样的如果他们声明的大小是一样的

d、 为了找到 MIN() or MAX()的值对于一个指定索引的列 key_col.

总之,就是经常用到的列就最好创建索引。

不能使用引用:

    a) 数据唯一性差(一个字段的取值只有几种时)的字段不要使用索引

        比如性别,只有两种可能数据。意味着索引的二叉树级别少,多是平级。这样的二叉树查找无异于全表扫描

b) 频繁更新的字段不要使用索引

        比如 logincount 登录次数,频繁变化导致索引也频繁变化,增大数据库工作量,降低效率

c) 字段不在 where 语句出现时不要添加索引,如果 where 后含 IS NULL /IS NOT NULL/ like ‘%输入符%’等条件,不建议使用索引只有在 where 语句出现,mysql 才会去使用索引

d) where 子句里对索引列使用不等于(<>),使用索引效果一般

索引失效:

a.如果条件中有 or,即使其中有条件带索引也不会使用(这也是为什么尽量少用 or 的原因)

注意:要想使用 or,又想让索引生效,只能将 or 条件中的每个列都加上索引

b.对于多列索引,不是使用的第一部分,则不会使用索引

c.like 查询是以%开头

d.如果列类型是字符串,那一定要在条件中将数据使用引号引用起来 否则不使用索引

e.如果 mysql 估计使用全表扫描要比使用索引快,则不使用索引

8,java 中的多线程在你们的这个项目当中有哪些体现?

a,后台任务:如定时向大量(100W 以上)的用户发送邮件;定期更新配置文件、任务调度

(如 quartz),一些监控用于定期信息采集

b, 自动作业处理:比如定期备份日志、定期备份数据库

c, 异步处理:如发微博、记录日志

Redis 分布式锁理解

回答:

实现思想

获取锁的时候,使用 setnx 加锁,并使用 expire 命令为锁添加一个超时时间,超过该时间则自动释放锁,锁的 value 值为一个随机生成的 UUID,通过此在释放锁的时候进行判断。

获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁。

释放锁的时候,通过 UUID 判断是不是该锁,若是该锁,则执行 delete 进行锁释放。

Redis 怎么设置过期的?项目过程中,使用了哪一种持久化方式

回答:

设置过期:

this.redisTemplate.expire("max",tempTime,TimeUnit.SECONDS);

持久化方式:Redis 默认的 RDB 方式

项目添加 Redis 缓存后,持久化具体怎么实现的。

答:

RDB:保存存储文件到磁盘;同步时间为 15 分钟,5 分钟,1 分钟一次,可能存在数据丢失问题。

AOF:保存命令文件到磁盘;安全性高,修改后立即同步或每秒同步一次。

上述两种方式在我们的项目中都有使用到,在广告轮播的功能中使用了 redis 缓存,先从 redis 中获取数据,无数据后从数据库中查询后保存到 redis 中

采用默认的 RDB 方式,在广告轮播的功能中使用了 redis 缓存,先从 redis 中获取数据,无数据就从数据库中查询后再保存到 redis 中

redis 能够存储的数据类型有哪几种? 

Redis 通过 SpringDataRedis 访问的. Redis 支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及 zset(sorted set: 有序集合)

怎样进行程序性能调优

系统性能就是两个事:

Throughput ,吞吐量。也就是每秒钟可以处理的请求数,任务数。

Latency, 系统延迟。也就是系统在处理一个请求或一个任务时的延迟。

那么 Latency 越好,能支持的 Throughput 就会越高。因为 Latency 短说明处理速度快,于是就可以处理更多的请求。

提高吞吐量:

        分布式集群,模块解藕,设计模式

系统延迟:

        异步通信


数据库设计的面试问题

你有了解 mysql 的隔离级别吗?mysql 默认的隔离级别是什么?

数据库事务的隔离级别有四种,隔离级别高的数据库的可靠性高,但并发量低,而隔离级别低的数据库可靠性低,但并发量高,系统开销小。

1. READ UNCIMMITTED(未提交读)

2. READ COMMITTED(提交读)

3. REPEATABLE READ(可重复读)

4. SERIALIZABLE(可串行化)

mysql 默认的事务处理级别是'REPEATABLE-READ',也就是可重复读。

sql 语句中关于查询语句的优化你们是怎么做的?

1、应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

2、对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

3、应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描

4、尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描

5、in 和 not in 也要慎用,否则会导致全表扫描

6、应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。

7、应尽量避免在 where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描

8、不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

9、在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使 用,并且应尽可能的让字段顺序与索引顺序相一致。

10、索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。

11、尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

12、任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回·用不到的任何字段。

mysql 索引失效的场景有哪些?like 做模糊查询的时候会失效吗?

1.WHERE 字句的查询条件里有不等于号(WHERE column!=…),MYSQL 将无法使用索引

2.类 似地, 如果 WHERE 字 句的查 询条件 里使用 了函数 (如: WHERE DAY(colu mn)=…), MYSQL 将 无法使 用索引

3.在 JOIN 操 作中(需要 从多个 数据表 提取数 据时 ),MYSQL 只有 在主键 和外键 的数 据类型 相同时 才能使 用索引 ,否则即使建立了索引也不会使用

4.如 果 WHERE 子 句的查 询条件 里使用 了比较 操作 符 LIKE 和 REGEXP, MYSQL只 有 在搜 索 模板 的第 一 个字 符不 是 通配 符的 情况 下 才能 使用 索 引。 比如 说 ,如 果查 询条件 是 LIKE  'abc%',MYSQL 将使 用索引 ;如果 条件 是 LIKE  '%abc',MYSQ L 将 不使用 索引。

5.在 ORDER BY 操 作中, MYSQL 只 有在排 序条件 不是一 个查询 条件表 达式的 情况 下 才使 用 索引 。尽 管 如此 ,在 涉 及多 个数 据表 的 查询 里, 即 使有 索引 可 用, 那些 索引在 加快 ORDER BY 操作方 面也没 什么作 用。

6.如 果某个 数据列 里包含 着许多 重复的 值,就 算为它 建立了 索引也 不会有 很好的 效果 。比如 说,如 果某个 数据列 里包含 了净是 些诸如 “0/1”或“Y/N”等 值,就 没有必 要为 它创建 一个索引。

7.索引有用 的情况下就太 多了。基本只要建立了索引,除了上面提到的索引不会使用的情况下之外 ,其他情况只要是使用在 WHERE条件里 ,ORDER  BY字段 ,联表字段,一般都是有效 的。 建立索引要的就 是有效果。不然还用它干 吗?如果不能确定在某 个字段上建立的索引是否有效果 , 只要实际进行测试下比较下执行 时间就知道。

8.如 果条件 中有 or(并且其 中有 or 的条 件是不 带索引 的), 即使其 中有条 件带索 引也 不会使 用(这 也是为 什么尽 量少用 or 的原 因)。 注意: 要想使用 or,又想让索 引生 效,只能将 or 条件 中的每 个列都 加上索 引

9.如果 列类 型是 字符 串, 那一 定要 在条 件中 将数 据使 用引 号引 用起 来,否则 不使 用索 引

10.如 果 mysql 估计 使用全 表扫描 要比使 用索引 快,则不 使用索 引

问 题二: Like 模糊查询,建立索引会失效

项目中关于表结构拆分,你们是业务层面的拆分还是表结构层面的拆分?

表结构层面的拆分。通过 mycat 数据库中间件完成数据库分表操作。

业务层面也有拆分,比如商品模块拆分成 8 张表来实现存储

有了解过大数据层面的分库分表吗?以及 mysql 的执行计划吗?

分库

通过 Mycat 结点来管理不同服务器上的数据库,每个表最多存 500 万条记录

分表

重直切割,水平切割

MySql 提供了 EXPLAIN 语法用来进行查询分析,在 SQL 语句前加一个"EXPLAIN"即可。mysql 中的 explain 语法可以帮助我们改写查询,优化表的结构和索引的设置,从而最大地提高查询效率。

有了解过数据库中的表级锁和行级锁吗?乐观锁和悲观锁你有哪些了解?

MySQL 的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。比如,MyISAM 和 MEMORY 存储引擎采用的是表级锁(table-level locking);InnoDB存储引擎既支持行级锁( row-level locking),也支持表级锁,但默认情况下是采用行级锁。

MySQL 主要的两种锁的特性可大致归纳如下:

表级锁: 开销小,加锁快;不会出现死锁(因为 MyISAM 会一次性获得 SQL 所需的全部锁);锁定粒度大,发生锁冲突的概率最高,并发度最低。

行级锁: 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

乐观锁:通过 version 版本字段来实现

悲观锁:通过 for update 来实现

Mysql 优化有没有工具

回答:

三个 MySQL 性能测试工具:The MySQL Benchmark Suite、MySQL super-smack、MyBench。除了第一个为 MySQL 性能测试工具,其他两个都为压力测试工具。

你们项目中使用到的数据库是什么?你有涉及到关于数据库到建库建表操作吗?数据库创建表的时候会有哪些考虑呢?

项目中使用的是 MySQL 数据库,

数据库创建表时要考虑

a、大数据字段最好剥离出单独的表,以便影响性能

b、使用 varchar,代替 char,这是因为 varchar 会动态分配长度,char 指定为 20,即时你存储字符“1”,它依然是 20 的长度

c、给表建立主键,看到好多表没主键,这在查询和索引定义上将有一定的影响

d、避免表字段运行为 null,如果不知道添加什么值,建议设置默认值,特别 int 类型,比如默认值为 0,在索引查询上,效率立显。

e、建立索引,聚集索引则意味着数据的物理存储顺序,最好在唯一的,非空的字段上建立,其它索引也不是越多越好,索引在查询上优势显著,在频繁更新数据的字段上建立聚集索引,后果很严重,插入更新相当忙。

f、组合索引和单索引的建立,要考虑查询实际和具体模式

mysql 中哪些情况下可以使用索引,哪些情况不能使用索引?mysql 索引失效的情形有哪些?

使用索引:

a、 为了快速查找匹配 WHERE 条件中涉及到列。

b、 如果表有一个 multiple-column 索引,任何一个索引的最左前缀可以通过使用优化器来查找行

c、 当运行 joins 时,为了从其他表检索行。MySql 可以更有效的使用索引在多列上如果他们声明的类型和大小是一样的话。在这个环境下,VARCHAR 和 CHAR 是一样的如果他们声明的大小是一样的

d、 为了找到 MIN() or MAX()的值对于一个指定索引的列 key_col.

            总之,就是经常用到的列就最好创建索引。

不能使用引用:

a) 数据唯一性差(一个字段的取值只有几种时)的字段不要使用索引

            比如性别,只有两种可能数据。意味着索引的二叉树级别少,多是平级。这样的二叉树查找无异于全表扫描

b) 频繁更新的字段不要使用索引

            比如 logincount 登录次数,频繁变化导致索引也频繁变化,增大数据库工作量,降低效率

c) 字段不在 where 语句出现时不要添加索引,如果 where 后含 IS NULL /IS NOT NULL/ like ‘%输入符%’等条件,不建议使用索引只有在 where 语句出现,mysql 才会去使用索引

d) where 子句里对索引列使用不等于(<>),使用索引效果一般

索引失效:

            a.如果条件中有 or,即使其中有条件带索引也不会使用(这也是为什么尽量少用 or 的原因)

                        注意:要想使用 or,又想让索引生效,只能将 or 条件中的每个列都加上索引

            b.对于多列索引,不是使用的第一部分,则不会使用索引

            c.like 查询是以%开头

            d.如果列类型是字符串,那一定要在条件中将数据使用引号引用起来 否则不使用索引

            e.如果 mysql 估计使用全表扫描要比使用索引快,则不使用索引

8,java 中的多线程在你们的这个项目当中有哪些体现?

            a,后台任务:如定时向大量(100W 以上)的用户发送邮件;定期更新配置文件、任务调度

                        (如 quartz),一些监控用于定期信息采集

            b, 自动作业处理:比如定期备份日志、定期备份数据库

            c, 异步处理:如发微博、记录日志

怎样进行数据库优化?

a,选取最适用的字段

                  在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。另外一个提高效率的方法是在可能的情况下,应该尽量把字段设置为 NOTNULL,

b,使用连接(JOIN)来代替子查询(Sub-Queries)

c,使用联合(UNION)来代替手动创建的临时表

d,事物:

                  a)要么语句块中每条语句都操作成功,要么都失败。换句话说,就是可以保持数据库中数据的一致性和完整性。事物以 BEGIN 关键字开始,COMMIT 关键字结束。在这之间的一条 SQL 操作失败,那么,ROLLBACK 命令就可以把数据库恢复到 BEGIN 开始之前的状态。

                  b) 是当多个用户同时使用相同的数据源时,它可以利用锁定数据库的方法来为用户提供一种安全的访问方式,这样可以保证用户的操作不被其它的用户所干扰。

e,锁定表

f,使用外键

                  锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。这个时候我们就可以使用外键。

g,使用索引

h,优化的查询语句

怎样进行数据库性能调优

 一应用程序优化

        (1)把数据库当作奢侈的资源看待,在确保功能的同时,尽可能少地动用数据库资源。

        (2)不要直接执行完整的 SQL 语法,尽量通过存储过程实现数据库操作。

        (3)客户与服务器连接时,建立连接池,让连接尽量得以重用,以避免时间与资源的损耗。

        (4)非到不得已,不要使用游标结构,确实使用时,注意各种游标的特性。

二基本表设计优化

(1)表设计遵循第三范式。在基于表驱动的信息管理系统中,基本表的设计规范是第三范式。

(2)分割表。分割表可分为水平分割表和垂直分割表两种:水平分割是按照行将一个表分割为多个表。

(3)引入中间表。

三 数据库索引优化

索引是建立在表上的一种数据组织,它能提高访问表中一条或多条记录的特定查询效率。

    聚集索引

            一种索引,该索引中键值的逻辑顺序决定了表中相应行的物理顺序。聚集索引确定表中数据的物理顺序。

    非聚集索引

            一种索引,该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同


分布式开发面试问题

分布式架构 session 共享问题,如何在集群里边实现共享。

         用了 CAS,所有应用项目中如果需要登录时在 web.xml 中配置过滤器做请求转发到cas 端工作原理是在 cas 登录后会给浏览器发送一个票据(ticket),浏览器 cookie 中会缓存这个 ticket,在登录其他项目时会拿着浏览器的 ticket 转发到 cas,到 cas 后根据票据判断是否登录

项目中如何配置集群?

        配置了 redis 集群,使用 redis3.0 版本官方推荐的配置方式

        solr 集群使用了 solrCloud,使用 zookeeper 关联 solrCloud 的配置文件zookeeper 也配置了集群

        应用层使用 Nginx 负载均衡

对分布式,dubbo,zookeeper 说的不太清楚

分布式是从项目业务角度考虑划分项目整个架构。可以将项目基于功能模块划分再分别部署。Dubbo 是实现分布式项目部署框架。在 zookeeper 是 dubbo 分布式框架的注册中心,管理服务的注册和调用。

从前端到后台的实现的过程描述的也不清楚

  项目前端采用 angularjs 框架在 controller 控制器中完成数据组装和数据展示,在服务层(service)代码完成中后台请求操作。后端基于前端的接口调用,完成数据的增删改查操作。前后端数据交互通过 json 格式字符串完成。

Dubbo 为什么选择 Zookeeper,而不选择 Redis

回答:

引入了 ZooKeeper 作为存储媒介,也就把 ZooKeeper 的特性引进来。

        首先是负载均衡,单注册中心的承载能力是有限的,在流量达到一定程度的时候就需要分流,负载均衡就是为了分流而存在的,一个 ZooKeeper 群配合相应的 Web 应用就可以很容易达到负载均衡;资源同步,单单有负载均衡还不够,节点之间的数据和资源需要同步,ZooKeeper 集群就天然具备有这样的功能;

        命名服务,将树状结构用于维护全局的服务地址列表,服务提供者在启动 的时候,向 ZK 上的指定节点/dubbo/${serviceName}/providers 目录下写入自己的 URL 地址,这个操作就完成了服务的发布。 其他特性还有 Mast 选举,分布式锁等。

项目中 Zookeeper 服务器挂了,服务调用可以进行吗?

回答:

可以的,消费者在启动时,消费者会从 zk 拉取注册的生产者的地址接口等数据,缓存在本地。

每次调用时,按照本地存储的地址进行调用

ActiveMq 消息被重复消费,丢失,或者不消费怎么办

回答:

重复消费:Queue 支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。

丢消息:用持久化消息,或者非持久化消息及时处理不要堆积,或者启动事务,启动事务后,commit()方法会负责任的等待服务器的返回,也就不会关闭连接导致消息丢失了。

不消费:去 ActiveMQ.DLQ 里找找

怎样解决 activeMQ 的消息持久化问题?

A:持久化为文件

          这个你装 ActiveMQ 时默认就是这种,只要你设置消息为持久化就可以了。涉及到的配置和代码有

                

                    

                

            producer.Send(request, MsgDeliveryMode.Persistent, level, TimeSpan.MinValue);

B:持久化为 MySql

    加载驱动 jar,为数据中创建三个数据库表,存储 activemq 的消息信息

如果 activeMQ 的消息没有发送成功,怎样确保再次发送成功。

重新传递消息的情况

ActiveMQ 在接收消息的 Client 有以下几种操作的时候,需要重新传递消息:

    1:Client 用了 transactions(事务),且在 session 中调用了 rollback()

    2:Client 用了 transactions,且在调用 commit()之前关闭

    3:Client 在 CLIENT_ACKNOWLEDGE 的传递模式下,在 session 中调用了 recover()

确保客户端有几种状态,检测状态,只要提交了那就说明客户端成功!

Zookeeper 怎样进行服务治理。

    接受提供者的接口信息和提供者 ip 地址进行存储,然后管理消费者和提供者之间调用关系!

如果 activeMQ 的服务挂了,怎么办?

      1、在通常的情况下,非持久化消息是存储在内存中的,持久化消息是存储在文件中的,它们的最大限制在配置文件的节点中配置。但是,在非持久化消息堆积到一定程度,内存告急的时候,ActiveMQ 会将内存中的非持久化消息写入临时文件中,以腾出内存。虽然都保存到了文件里,但它和持久化消息的区别是,重启后持久化消息会从文件中恢复,非持久化的临时文件会直接删除。

    2、考虑高可用,实现 activemq 集群。

如果 zookeeper 服务挂了怎么办?

            注册中心对等集群,任意一台宕掉后,会自动切换到另一台

            注册中心全部宕掉,服务提供者和消费者仍可以通过本地缓存通讯

            服务提供者无状态,任一台宕机后,不影响使用

            服务提供者全部宕机,服务消费者会无法使用,并无限次重连等待服务者恢复

Dubbo 有 3 次重试,假如新消息被重复消费怎么处理

回答:

        1、去掉超时重试机制

        2、服务端增加幂等校验,服务器加入校验机制,如果这个消息已被 消费就不再重复消费

mq 消费者接收不到消息怎么办。

Mq 消费者接受不到消息存在 2 中情况:

1. 处理失败 指的是 MessageListener 的 onMessage 方法里抛出 RuntimeException。

2. Message 头里有两个相关字段:Redelivered 默认为 false,redeliveryCounter 默认为 0。

3. 消息先由 broker 发送给 consumer,consumer 调用 listener,如果处理失败,本地 redeliveryCounter++,给 broker 一个特定应答,broker 端的 message 里 redeliveryCounter++,延迟一点时间继续调用,默认1s。超过 6 次,则给 broker 另一个特定应答,broker 就直接发送消息到 DLQ。

4. 如果失败 2 次,consumer 重启,则 broker 再推过来的消息里,redeliveryCounter=2,本地只能再重试 4 次即会进入 DLQ。

5. 重 试 的 特 定 应 答 发 送 到 broker , broker 即 会 在 内 存 将 消 息 的 redelivered 设 置 为 true ,redeliveryCounter++,但是这两个字段都没有持久化,即没有修改存储中的消息记录。所以 broker重启时这两个字段会被重置为默认值。

系统的高并发问题是怎么解决的。

并发问题高,这个问题的解决方案是一个系统性的,系统的每一层面都需要做优化:

1) 数据层

    a)   集群

    b) 分表分库

    c) 开启索引

    d) 开启缓存

    e) 表设计优化

    f) Sql 语句优化

    g) 缓存服务器(提高查询效率,减轻数据库压力)

    h) 搜索服务器(提高查询效率,减轻数据库压力)

2) 项目层

    a) 采用面向服务分布式架构(分担服务器压力,提高并发能力)

    b) 采用并发访问较高的详情系统采用静态页面

    c) 使用页面缓存

    d) 用 ActiveMQ 使得业务进一步进行解耦,提高业务处理能力

    e) 使用分布式文件系统存储海量文件

3) 应用层

    a) Nginx 服务器来做负载均衡

    b) Lvs 做二层负载

并发数多少,项目中怎么解决并发问题?

面试中项目的并发数不宜说的过大,安装目前品优购项目拆分规模,这个项目的并发是在10000+,但是学生面试不能说的这么高。

可以有以下 2 方面的回答:

    1) 项目并发并不清楚(只是底层程序员)

    2) 参与核心业务设计,知道并发是多少(测试峰值,上线并发)3000---5000 吧

    面对项目高并发,项目必须做各种优化措施了:

 4) 数据层

    a) 集群

    b) 分表分库

    c) 开启索引

    d) 开启缓存

    e) 表设计优化

    f) Sql 语句优化

    g) 缓存服务器(提高查询效率,减轻数据库压力)

    h) 搜索服务器(提高查询效率,减轻数据库压力)

5) 项目层

    a) 采用面向服务分布式架构(分担服务器压力,提高并发能力)

    b) 采用并发访问较高的详情系统采用静态页面

    c) 使用页面缓存

    d) 用 ActiveMQ 使得业务进一步进行解耦,提高业务处理能力

    e) 使用分布式文件系统存储海量文件

6) 应用层

    a) Nginx 服务器来做负载均衡

    b) Lvs 做二层负载

消息发送失败怎么处理,发送数据,数据库已经保存了数据,但是 redis 中没有同步,怎么办。或者说如何做到消息同步。

消息发送失败,可以进行消息的重新发送,可以配置消息的重发次数。

爱思乐电商项目常见问题(下)_第4张图片

如果消息重发完毕后,消息还没有接受成功,重启服务。

Dubbo 的通信原理?

Dubbo 底层使用 hessain2 进行二进制序列化进行远程调用

Dubbo 底层使用 netty 框架进行异步通信。NIO


其他技术面试问题

单点登录的访问或者跨域问题

首先要理解什么是单点登录。单点登录是相互信任的系统模块登录一个模块后,其他模块不需要重复登录即认证通过。项目采用的是 CAS 单点登录框架完成的。首先 CAS 有两大部分。客户端和服务端。服务端就是一个 web 工程部署在 tomcat 中。在服务端完成用户认证操作。每次访问系统模块时,需要去 CAS 完成获取 ticket。当验证通过后,访问继续操作。对于 CAS 服务端来说,我们访问的应用模块就是 CAS 客户端。

跨域问题,首先明白什么是跨域。什么时候涉及跨域问题。当涉及前端异步请求的时候才涉及跨域。那什么是跨域呢?当异步请求时,访问的请求地址的协议、ip 地址、端口号任意一个与当前站点不同时,就会涉及跨域访问。解决方案:1、jQuery 提供了 jsonp 实现 2、W3C 标准提供了 CORS(跨域资源共享)解决方案。

shiro 安全认证时如何做的

要明白 shiro 执行流程以及 shiro 的核心组件,可参考下图

爱思乐电商项目常见问题(下)_第5张图片

认证过程:

在 application  Code 应用程序中调用 subject 的 login 方法。将页面收集的用户名和密码传给安全管理器 securityManager,将用户名传给 realm 对象。Realm 对象可以理解为是安全数据桥,realm 中认证方法基于用户名从数据库中查询用户信息。如果用户存在,将数据库查询密码返回给安全管理器 securityManager,然后安全管理器判断密码是否正确。

solr 的用途

solr 在系统中主要完成商品搜索功能,提高搜索性能。

分布式锁的问题

针对分布式锁的实现,目前比较常用的有以下几种方案:

1.基于数据库实现分布式锁

2.基于缓存(redis,memcached,tair)实现分布式锁

3.基于 zookeeper 实现分布式锁

solr 索引中使用了 IK 分词器,你们项目中使用到了分词器的哪种工作模式?

IK 分词器,基本可分为两种模式,一种为 smart 模式,一种为非 smart 模式。

例如:张三说的确实在理

smart 模式的下分词结果为:

张三 | 说的 | 确实 | 在理

而非 smart 模式下的分词结果为:

张三 | 三 | 说的 | 的确 | 的 | 确实 | 实在 | 在理

可见非 smart 模式所做的就是将能够分出来的词全部输出;smart 模式下,IK 分词器则会根据内在方法输出一个认为最合理的分词结果,这就涉及到了歧义判断。

项目中采用的是 smart 模块分词的。

java 中关于多线程的了解你有多少?线程池有涉及吗?

同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。线程分为五个阶段:创建、就绪、运行、阻塞、终止。

Java 线程有五种基本状态

新建 状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

就绪状态(Runnable):当调用线程对象的 start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待 CPU 调度执行,并不是说执行了 t.start()此线程立即就会执行;

运行状态(Running):当 CPU 开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对 CPU 的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被 CPU 调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

1.等待阻塞:运行状态中的线程执行 wait()方法,使本线程进入到等待阻塞状态;

2.同步阻塞 -- 线程在获取 synchronized 同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

3.其他阻塞 -- 通过调用线程的 sleep()或 join()或发出了 I/O 请求时,线程会进入到阻塞状态。当 sleep()状态超时、join()等待线程终止或者超时、或者 I/O 处理完毕时,线程重新转入就绪状态。

死亡状态(Dead):线程执行完了或者因异常退出了 run()方法,该线程结束生命周期。

Java 中线程的创建常见有如三种基本形式

1.继承 Thread 类,重写该类的 run()方法。

2.实现 Runnable 接口,并重写该接口的 run()方法,该 run()方法同样是线程执行体,创建 Runnable 实现类的实例,并以此实例作为 Thread类的 target 来创建 Thread 对象,该 Thread 对象才是真正的线程对象。

3.使用 Callable 和 Future 接口创建线程。

具体是创建 Callable 接口的实现类,并实现 clall()方法。并使用 FutureTask 类来包装 Callable 实现类的对象,且以此 FutureTask 对象作为 Thread 对象的 target 来创建线程。

线程池:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。

如何实现线程的同步?

为何要使用同步?

  java 允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证了该变量的唯一性和准确性。

线程同步(5 种同步方式)

1.同步方法 2.同步代码块 3.使用特殊域变量(volatile)实现线程同步 4.使用重入锁实现线程同步 5.使用局部变量实现线程同步

遍历 hashmap 有几种方式?

Map 的四种遍历方式

(1) for each map.entrySet()

(2) 显示调用 map.entrySet()的集合迭代器

(3) for each map.keySet(),再调用 get 获取

(4) for each map.entrySet(),用临时变量保存 map.entrySet()

简单介绍一下 solr 全文检索在整个系统中的应用,在更新索引库的同时会产生索引碎片,这个碎片是如何处理的?

根据商品的名称,分类,品牌等属性来创建索引进行商品搜索。

更新索引库时会先删除索引,然后再重建。而对于删除聚集索引,则会导致对应的非聚集索引重建两次(删除时重建,建立时再重建).

直接删除碎片。

java 并发包下有哪些并发组件?

分为两层组成

外层框架主要有 Lock(ReentrantLock、ReadWriteLock 等)、同步器(semaphores 等)、阻塞队列

(BlockingQueue 等)、Executor(线程池)、并发容器(ConcurrentHashMap 等)、还有 Fork/Join 框架;

  内层有 AQS(AbstractQueuedSynchronizer 类,锁功能都由他实现)、非阻塞数据结构、原子变量类(AtomicInteger 等无锁线程安全类)三种。

讲一下 jvm 调优。

a,堆大小设置

b,回收器选择

c,辅助信息

JVM 提供了大量命令行参数,打印信息,供调试使用;

讲一下 jvm 的组成。

JVM 由类加载器子系统、运行时数据区、执行引擎以及本地方法接口组成

讲一下 ThreadLocal 类。

  ThreadLocal,很多地方叫做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多。可能很多朋友都知道 ThreadLocal 为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量;

ThreadLocal 在每个线程中对该变量会创建一个副本,即每个线程内部都会有一个该变量,且在线程内部任何地方都可以使用,线程之间互不影响,这样一来就不存在线程安全问题,也不会严重影响程序执行性能。

但是要注意,虽然 ThreadLocal 能够解决上面说的问题,但是由于在每个线程中都创建了副本,所以要考虑它对资源的消耗,比如内存的占用会比不使用 ThreadLocal 要大;

Solr 热搜索

回答:

和 Redis 热搜索一样将经常搜索的词,新建 collection,对这些搜索内容单独进行索引。

简单介绍一下 solr 全文检索在整个系统中的应用,在更新索引库的同时会产生索引碎片,这个碎片是如何处理的?

根据商品的名称,分类,品牌等属性来创建索引进行商品搜索。

更新索引库时会先删除索引,然后再重建。而对于删除聚集索引,则会导致对应的非聚集索引

重建两次(删除时重建,建立时再重建).

直接删除碎片。

怎么确保 session 共享?

在分布式项目中实现 session 共享必须做以下准备工作:

1) Cookie 中共享 ticket

2) Redis 存储 session

分布式系统共享用户身份信息 session,必须先获取 ticket 票据,然后再根据票据信息获取 redis 中用户身份信息。

实现以上 2 点即可实现 session 共享。

爱思乐电商项目常见问题(下)_第6张图片

目前项目中使用的 springsecurity + cas 来实现的单点登录,cas 自动产生 ticket 票据信息,每次获取

用户信息,cas 将会携带 ticket 信息获取用户身份信息。

项目中哪块涉及了线程问题,怎么处理的?

项目的高并发访问就是一个多线程问题。

项目中普通的业务开发基本没有涉及多线程问题,不过你可以谈谈你使用的框架中使用的多线程技术:

因为我们项目使用的框架进行开发的,因此多线程处理多让框架非我们处理结束了。

1) 高并发就是多线程,这里的多线程让 servlet 服务器给处理了谈谈 Tomcat 多线程配置;

    a) 配置线程池,扩大并发能力

    b) 开启 NIO 能力等等

2) 框架多线程:mybatis 框架底层使用的连接池

传统 IO 和 NIO 的区别?

IO 是直接通信

NIO 是由缓存作为中间层,先把数据放入缓存(内存),数据的消防者可以从缓存中获取数据。

你可能感兴趣的:(爱思乐电商项目常见问题(下))