面试题答案
一键面试1. 数据模型设计
1.1 行键设计
- 对于电商平台订单历史记录,行键可以设计为一个复合键。例如,采用
时间戳(倒序) + 用户ID + 订单ID
的方式。时间戳倒序排列可以让新订单记录排在前面,便于快速查询最新订单。用户ID放在中间,方便按用户维度进行范围查询。订单ID作为唯一标识确保每行数据的唯一性。如:1672531200000_123456_789012
。
1.2 列族设计
- 基本信息列族:存储订单的基本信息,如订单金额、下单时间(如果行键中的时间戳精度不够,可在此处补充更详细时间)、订单状态等。例如:
列名:order_amount 值:100.00 列名:order_time 值:2023 - 01 - 01 12:00:00 列名:order_status 值:paid
- 商品信息列族:如果订单中包含多个商品,可以采用JSON格式存储商品详细信息,如商品ID、商品名称、数量、单价等。例如:
列名:products 值:[{"product_id": "123", "product_name": "手机", "quantity": 1, "unit_price": 5000}, {"product_id": "456", "product_name": "充电器", "quantity": 1, "unit_price": 100}]
2. 拓展HTable实用方法
2.1 批量写入优化
- 使用
HTable
的put(List<Put>)
方法进行批量写入。在高并发订单写入场景下,将多个Put
对象批量收集,然后一次性写入HBase,减少HBase的I/O次数,提高写入性能。 - 例如:
List<Put> putList = new ArrayList<>(); for (Order order : orderList) { Put put = new Put(Bytes.toBytes(order.getRowKey())); put.addColumn(Bytes.toBytes("basic_info"), Bytes.toBytes("order_amount"), Bytes.toBytes(order.getOrderAmount())); put.addColumn(Bytes.toBytes("basic_info"), Bytes.toBytes("order_status"), Bytes.toBytes(order.getOrderStatus())); // 其他列添加 putList.add(put); } hTable.put(putList);
2.2 多维度查询优化
- 对于按时间范围、订单状态、用户ID等多维度查询,可以利用HBase的过滤器(Filter)。
- 按时间范围查询:可以通过
RowFilter
结合BinaryComparator
来实现。例如,查询2023年1月1日到2023年2月1日的订单,先构造两个行键范围边界值(根据行键设计中的时间戳部分),然后使用RowFilter
进行过滤。 - 按订单状态查询:可以使用
SingleColumnValueFilter
,指定列族为basic_info
,列名为order_status
,以及要查询的订单状态值。例如,查询状态为paid
的订单:SingleColumnValueFilter filter = new SingleColumnValueFilter( Bytes.toBytes("basic_info"), Bytes.toBytes("order_status"), CompareFilter.CompareOp.EQUAL, Bytes.toBytes("paid") );
- 按用户ID查询:结合行键设计,通过
RowFilter
和SubstringComparator
可以查询指定用户ID的订单。例如:RowFilter rowFilter = new RowFilter(CompareFilter.CompareOp.EQUAL, new SubstringComparator("_123456_"));
3. 整体架构设计思路
3.1 缓存设计
- 读缓存:在查询订单历史记录时,引入缓存(如Redis)。当接收到查询请求时,先从Redis中查询,如果缓存中有数据则直接返回,减少对HBase的读压力。对于热点订单数据(如近期大量查询的用户订单),缓存可以设置较长的过期时间。
- 写缓存:对于高并发的订单写入,可以在应用层先将订单数据缓存到内存队列(如Kafka)中,然后由专门的消费者从队列中取出数据批量写入HBase。这样可以对写入流量进行削峰填谷,提高HBase写入稳定性。
3.2 计算框架结合
- 数据分析:当需要对订单历史记录进行复杂分析(如统计不同时间段的订单金额总和、不同用户的订单数量等)时,可以结合计算框架(如Spark)。Spark可以直接读取HBase中的数据,利用其分布式计算能力进行复杂分析。分析结果可以存储回HBase或其他存储(如MySQL)中供前端展示。
- 实时计算:对于实时订单数据分析,如实时统计订单数量、实时监控订单状态变化等,可以使用Flink等实时计算框架。Flink可以消费Kafka中的订单数据,进行实时处理和分析,处理结果可用于实时报表展示或触发实时业务逻辑。
3.3 数据流向
- 订单写入:应用程序将订单数据发送到Kafka队列,Kafka消费者从队列中取出数据,经过整理和批量处理后写入HBase。
- 订单查询:应用程序接收到查询请求,先查询Redis缓存,如果缓存未命中,则查询HBase。查询结果可以选择性地更新到Redis缓存中。
- 数据分析:Spark或Flink从HBase读取数据进行分析,分析结果存储到相应的存储系统中供展示或其他业务使用。