草庐IT

大数据面试重点之kafka(三)

大数据小理 2023-07-18 原文

Kafka如何保证全局有序?
可回答:1)Kafka消费者怎么保证有序性?2)Kafka生产者写入数据怎么保证有序?3)Kafka可以保证 数据的局部有序,如何保证数据的全局有序?4)Kafka消息的有序性
问过的一些公司:快手x3,360x2,安恒信息,京东,京东(2021.07),重庆富民银行(2021.09) 参考答案:
1、设置Key值,指定分区
kafka分区是存在K和V的,K就是分区,一般都是默认的,而默认的经常会发生一些我们并不像看到的结 果,例如对同一数据进行多次操作不同分区会导致后进入先出,这就是因为跨分区导致的结果,因此我 们要设置key用来进行hash取模来确定分区,并且,这个再kafka源码是存在的,就在DefaultPartitioner.java中。

通过源码我们可以发现,再源码中默认的key为空,则系统会运算出一个partition,如果用这种方式,那 么,就会导致分区内有序而分区无序,会导致数据无序,因此,要指定一个key值,也就是指定分区, 这样的话,同一个数据发送到同一个分区,而多个分区依旧可以并行,同时实现数据有序和多分区并 行。
如果数据是从MySQL传过来的话,一般来说都是会有自增长主键的,我们可以直接读取主键来作为运算 的key值进行操作,这样就可以保证数据的操作唯一性了。
2、 max.in.flight.requests.per.connection 设置为1
max.in.flight.requests.per.connection 设置为1,每个批次里面一次只写入一条消息到kafka里面,而这个参数,在kafka官网中是有说明的:

官网已经说的很明显了,如果设置打于1,那么每次重试可能存在从新排序(乱序)的情况,比如我设 置为5,那么我传输的过程应该是1,2,3,4,5。
但是如果网络波动导致3丢失,那么kafka自动重试只会拉取3,也就是排序就成了1,2,4,5,3。 所以,记得将每个批次的消息数设置为1,防止出现重试乱序的情况。
3、设置重试次数大于100次
每一次kafka操作为了防止网络延时等问题,要设置重试次数大于100次

生产者消费者模式与发布订阅模式有何异同?
问过的一些公司:百度

参考答案:
1、点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除)
消息生产者生产消息发送到Queue中,然后消息消费者从Queue中取出并且消费消息。
消息被消费以后,Queue中不再有存储,所以消息消费者不可能消费到已经被消费的消息。Queue支持 存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。

2、发布/订阅模式(一对多,消费者消费数据之后不会清除消息)
消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点模式 不同,发布到topic的消息会被所有订阅者消费。

Kafka的消费者组是如何消费数据的
问过的一些公司:京东参考答案:
Consumer Group (CG)
消费者组,由多个consumer组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一 个消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一 个订阅者。

Kafka的oGset管理
问过的一些公司:招银网络参考答案:

消费者在消费的过程中需要记录自己消费了多少数据,即消费 Offset。Kafka Offset 是Consumer Position,与 Broker 和 Producer 都无关。每个 Consumer Group、每个 Topic 的每个Partition 都有各自的Offset,如下图所示。


通常有如下几种 Kafka Offset 的管理方式:
Spark Checkpoint:在Spark Streaming 执行Checkpoint 操作时,将Kafka Offset 一并保存到HDFS 中。这种方式的问题在于:当Spark Streaming 应用升级或更新时,以及当Spark 本身更新时, Checkpoint 可能无法恢复。因而,不推荐采用这种方式。
HBASE、Redis 等外部NOSQL 数据库:这一方式可以支持大吞吐量的Offset 更新,但它最大的问题在于:用户需要自行编写HBASE 或Redis 的读写程序,并且需要维护一个额外的组件。ZOOKEEPER:老版本的位移offset是提交到zookeeper中的,目录结构是
: /consumers/<group.id>/offsets/ / ,但是由于ZOOKEEPER 的写入能力并不会随着ZOOKEEPER 节点数量的增加而扩大,因而,当存在频繁的Offset 更新时, ZOOKEEPER 集群本身可能成为瓶颈。因而,不推荐采用这种方式。
Kafka自身的一个特殊Topic( consumer_offsets)中:这种方式支持大吞吐量的Offset更新,又不需要手动编写Offset 管理程序或者维护一套额外的集群,因而是迄今为止最为理想的一种实现方式。


另外几个与 Kafka Offset 管理相关的要点如下:
Kafka 默认是定期帮你自动提交位移的(enable.auto.commit=true)。有时候,我们需要采用自己来管理位移提交,这时候需要设置 enable.auto.commit=false。
属性 auto.offset.reset 值含义解释如下:
earliest :当各分区下有已提交的Offset 时,从“提交的Offset”开始消费;无提交的Offset 时, 从头开始消费;
latest : 当各分区下有已提交的Offse`t 时,从提交的Offset 开始消费;无提交的Offset时,消费新产生的该分区下的数据;
none : Topic 各分区都存在已提交的Offset 时,从Offset 后开始消费;只要有一个分区不存在已提交的Offset,则抛出异常。

  1. kafka-0.10.1.X版本之前: auto.offset.reset 的值为smallest,和,largest.(offest保存在zk 中);
  2. kafka-0.10.1.X版本之后: auto.offset.reset 的值更改为:earliest,latest,和none (offest保存在kafka的一个特殊的topic名为: consumer_offsets里面);

Kafka为什么同一个消费者组的消费者不能消费相同的分区?
问过的一些公司:网易参考答案:
Kafka通过消费者组机制同时实现了发布/订阅模型和点对点模型。多个组的消费者消费同一个分区属于 多订阅者的模式,自然没有什么问题;而在单个组内某分区只交由一个消费者处理的做法则属于点对点 模式。其实这就是设计上的一种取舍,如果Kafka真的允许组内多个消费者消费同一个分区,也不是什 么灾难性的事情,只是没什么意义,而且还会重复消费消息。
通常情况下,我们还是希望一个组内所有消费者能够分担负载,让彼此做的事情没有交集,做一些重复 性的劳动纯属浪费资源。就如同电话客服系统,每个客户来电只由一位客服人员响应。那么请问我就是 想让多个人同时接可不可以?当然也可以了,技术上没什么困难,只是这么做没有任何意义罢了,既拉 低了整体的处理能力,也造成了人力成本的浪费。
总之,这种设计不是出于技术上的考量而更多还是看效率等非技术方面。

如果有一条oGset对应的数据,消费完成之后,手动提交失败,如何处理?
问过的一些公司:安恒信息参考答案:
回滚,利用Kafka的事务解决。

正在消费一条数据,Kafka挂了,重启以后,消费的oGset是哪一个
问过的一些公司:招银网络参考答案:

可以在Java API中设置 auto.offset.reset 的值(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG)来进行指定。
先来看几个测试实验,结论在最后会给出
auto.oGset.reset值含义解释
earliest :当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费
:当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的 该分区下的数据
latest
none :topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的
offset,则抛出异常
案例测试如下:
1、同分组测试

  1. 测试一
    测试环境:Topic为lsztopic7,并生产30条信息。lsztopic7详情:


创建组为“testtopi7”的consumer,将enable.auto.commit设置为false,不提交offset。依次更改
auto.offset.reset的值。此时查看offset情况为:

![earliest:客户端读取30条信息,且各分区的offset从0开始消费。latest: 客 户 端 读 取 0 条 信 息 。 none:抛出NoOffsetForPartitionException异常。
测试结论:

  1. 新建一个同组名的消费者时,auto.offset.reset值含义:
  2. earliest 每个分区是从头开始消费的。
  3. none 没有为消费者组找到先前的offset值时,抛出异常
  4. 测试二
    测试环境:测试场景一下latest时未接受到数据,保证该消费者在启动状态,使用生产者继续生产10条数 据,总数据为40条。

    测试结果:

latest:客户端取到了后生产的10条数据
测试结论:

1 当创建一个新分组的消费者时,auto.offset.reset值为latest时,表示消费新的数据(从consumer创建 开始,后生产的数据),之前产生的数据不消费。

  1. 测试三
    测试环境:在测试环境二,总数为40条,无消费情况下,消费一批数据。运行消费者消费程序后,取到
    5条数据。 即,总数为40条,已消费5条,剩余35条。

测试结果:
earliest:消费35条数据,即将剩余的全部数据消费完。
latest:

  1. 消费9条数据,都是分区3的值。
  2. offset:0 partition:3
  3. offset:1 partition:3
  4. offset:2 partition:3
  5. offset:3 partition:3
  6. offset:4 partition:3
  7. offset:5 partition:3
  8. offset:6 partition:3
  9. offset:7 partition:3
  10. offset:8 partition:3
    none:抛出NoOffsetForPartitionException异常

测试结论:

  1. earliest:当分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消 费。

  2. latest:当分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该 分区下的数据。

  3. none:当该topic下所有分区中存在未提交的offset时,抛出异常。

  4. 测试四
    测试环境:再测试三的基础上,将数据消费完,再生产10条数据,确保每个分区上都有已提交的
    offset。此时,总数为50,已消费40,剩余10条

    测试结果:
    none:

  5. 消费10条信息,且各分区都是从offset开始消费

  6. offset:9 partition:3

  7. offset:10 partition:3

  8. offset:11 partition:3

  9. offset:15 partition:0

  10. offset:16 partition:0

  11. offset:17 partition:0

  12. offset:18 partition:0

  13. offset:19 partition:0

  14. offset:20 partition:0

  15. offset:5 partition:2
    测试结论:

1 值为none时,topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交 的offset,则抛出异常。
2、不同分组下测试
1)测试五
测试环境:在测试四环境的基础上:总数为50,已消费40,剩余10条,创建不同组的消费者,组名为
testother7。

测试结果:
earliest:消费50条数据,即将全部数据消费完。
latest:消费0条数据。
none:抛出异常

测试结论:

  1. 组与组间的消费者是没有关系的。
  2. topic中已有分组消费数据,新建其他分组ID的消费者时,之前分组提交的offset对新建的分组消费不起作 用。
    3、总结

    从上面的实验来看,基本上对auto.offset.reset不同的值进行了测试根据下面的实验数据来进行分析
    CURRENT-OFFSET:表示消费者消费了数据之后提交的offset,即消费者消费了的数据的偏移量。如果为unknown,则表示消费者未提交过offset。
    LOG-END-OFFSET:表示的是该分区的HW。

LAG:表示延迟滞后,也就是生产者已经写到kafka集群了,然后有还没有被消费的数量,是logSize- currentOffset,logsize指的是消息总数。
得出以下的一些结论:

  1. 如果CURRENT-OFFSET不是为unknown(消费者以前消费过数据,提交过offset),重启消费者时
    earliest、latest、none都是会从CURRENT-OFFSET一直消费到LOG-END-OFFSET。也就是不会更新offset。
  2. 如果CURRENT-OFFSET为unknown,重启消费者时earliest、latest、none才会展现出他们各自的不同:
    earliest:会从该分区当前最开始的offset消息开始消费(即从头消费),如果最开始的消息offset是0,那么消费者的offset就会被更新为0. latest:只消费当前消费者启动完成后生产者新生产的数据。旧数据不会再消费。offset被重置为分 区的HW。
    none:启动消费者时,该消费者所消费的主题的分区没有被消费过,就会抛异常。(一般新建主题 或者用新的消费者组是使用这个就会抛异常。。宕机重启的话,使用这个就没问题。。这个的作用 是什么?我猜测应该是用于在重启消费者时检查该消费者所消费的主题以及所属的消费者组的名称 是否写错了,导致该消费者没有消费原来主题分区)
    这里再强调一遍:
    在Java API中设置auto.offset.reset值(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG)。

Kafka支持什么语义,怎么实现Exactly Once?
可回答:
问过的一些公司:网易,快手 x 2
参考答案:
Kafka支持的消费语义有以下几种:
at most once:最多消费一次,消息可能会丢失 log日志
at least once:至少消费一次,但是会重复消费例如手动异步提交offset exactly once:正好一次,不丢失,不重复

  1. 至少一次:at-least-once 表示的是关闭offset自动提交功能,消费端在消费数据的时候很可能在commitAync之前,已经保存在数据库,但是这个时候服务器宕机了,从而导致offset不能提交成功。这 个时候再次启动消费者的时候,还是会再次写入数据库,也就是至少一次会重复消费,至少不会丢数 据。
  2. 至多一次:at-most-once 表示有可能是0次或者1次,可以选择开启自动提交offset的功能,然后把自动提交offset的时间设置一下,有可能消费者在消费的时间段内就到了自动提交的时间,从而导致了 offset已经提交了,但是数据库保存还没进行。下一次再消费的时候就会认为offset已经成功了,直接丢 弃消息。就会造成丢数据。
  3. 仅一次:exactly-once 表示数据仅被消费一次,还是开启自动开启offset提交的功能,可以开启consumer.seek()方法,相当于自己处理分区和offset,可以在此基础上开启事务,保持原子性,只有数据 库保存成功再提交offset,保证两者同时成功。
    Exactly Once语义
    将服务器的ACK级别设置为-1,可以保证Producer到Server之间不会丢失数据,即At Least Once语义。相对的,将服务器ACK级别设置为0,可以保证生产者每条消息只会被发送一次,即At Most Once语义。

At Least Once可以保证数据不丢失,但是不能保证数据不重复;相对的,At Least Once可以保证数据不重复,但是不能保证数据不丢失。但是,对于一些非常重要的信息,比如说交易数据,下游数据消费者 要求数据既不重复也不丢失,即Exactly Once语义。在0.11版本以前的Kafka,对此是无能为力的,只能保证数据不丢失,再在下游消费者对数据做全局去重。对于多个下游应用的情况,每个都需要单独做全 局去重,这就对性能造成了很大影响。
0.11版本的Kafka,引入了一项重大特性:幂等性。所谓的幂等性就是指Producer不论向Server发送多少 次重复数据,Server端都只会持久化一条。幂等性结合At Least Once语义,就构成了Kafka的Exactly Once语义。即:
At Least Once + 幂等性 = Exactly Once
要启用幂等性,只需要将Producer的参数中enable.idompotence设置为true即可。Kafka的幂等性实现其 实就是将原来下游需要做的去重放在了数据上游。开启幂等性的Producer在初始化的时候会被分配一个PID,发往同一Partition的消息会附带Sequence Number。而Broker端会对<PID, Partition, SeqNumber>做缓存,当具有相同主键的消息提交时,Broker只会持久化一条。
但是PID重启就会变化,同时不同的Partition也具有不同主键,所以幂等性无法保证跨分区跨会话的
Exactly Once。

Kafka的消费者和消费者组有什么区别?为什么需要消费者组?
可回答:说下Kafka的消费者和消费者组,以及它们的作用是什么? 问过的一些公司:字节,电信云计算,京东,拼多多,bigo
参考答案:
1、什么是消费者
顾名思义,消费者就是从kafka集群消费数据的客户端,如下图,展示了一个消费者从一个topic中消费 数据的模型

2、为什么需要消费者组
如果这个时候 kafka 上游生产的数据很快,超过了这个 消费者1 的消费速度,那么就会导致数据堆积, 产生一些大家都知道的蛋疼事情了,那么我们只能加强 消费者 的消费能力,所以也就有了
消费者

组 。
3、什么是消费者组
所谓 消费者组 ,其实就是一组 消费者 的集合,当我们看到下面这张图是不是就特别舒服了,我们采 用了一个 消费组 来消费这个 topic ,众人拾柴火焰高,其消费能力那是按倍数递增的,所以这里我们
单消费者

一般来说都是采用 消费者组 来消费数据,而不会是
注意:
来消费数据的。

一个topic可以被多个消费者组消费,但是每个消费者组消费的数据是互不干扰的,也就是说,每个消费 组消费的都是完整的数据 。
一个分区只能被同一个消费组内的一个消费者消费,而不能拆给多个消费者消费,也就是说如果你某个 消费者组内的消费者数比该 Topic 的分区数还多,那么多余的消费者是不起作用的

扩展一下:

  1. 是不是一个消费组的消费者越多其消费能力就越强呢?
    从下图我们就可以很好的可以回答这个问题了,我们可以看到消费者4是完全没有消费任何的数据的, 所以如果你想要加强消费者组的能力,除了添加消费者,分区的数量也是需要跟着增加的,只有这样他 们的并行度才能上的去,消费能力才会强。

    为了提高消费组的消费能力,我是不是可以随便添加分区和消费者呢?
    答案当然是否定的。。。我们看到下图,一般来说我们建议消费者数量和分区数量是一致的,当我们的 消费能力不够时,就必须通过调整分区的数量来提高并行度,但是,我们应该尽量来避免这种情况发 生。
    比如:现在我们需要在下图的基础上增加一个分区4,那么这个分区4该由谁来消费呢?这个时候kafka会 进行分区再均衡,来为这个分区分配消费者,分区再均衡期间该Topic是不可用的,并且作为一个被消费 者,分区数的改动将影响到每一个消费者组 ,所以在创建 topic 的时候,我们就应该考虑好分区数,来尽量避免这种情况发生。


Kafka producer的写入数据过程?
问过的一些公司:流利说参考答案:
Kafka的Producer发送消息采用的是异步发送的方式。在消息发送的过程中,涉及到了两个线程——main 线程和Sender线程,以及一个线程共享变量——RecordAccumulator。main线程将消息发送给RecordAccumulator,Sender线程不断从RecordAccumulator中拉取消息发送到Kafka broker。

相关参数
batch.size:只有数据积累到batch.size之后,sender才会发送数据。 linger.ms:如果数据迟迟未达到batch.size,sender等待linger.time之后就会发送数据。

有关大数据面试重点之kafka(三)的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  3. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  4. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  5. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  6. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  7. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  8. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  9. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  10. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

随机推荐