精华内容
下载资源
问答
  • 常见的消息结尾方式
    千次阅读
    2020-09-10 09:22:10

    Sqlserver Manager 连接报错:

    有关调用实时(JIT)调试而不是此对话框的详细信息,
    请参见此消息的结尾

    有关调用实时(JIT)调试而不是此对话框的详细信息,
    请参见此消息的结尾。
    
    ************** 异常文本 **************
    Microsoft.SqlServer.Management.RegisteredServers.RegisteredServerException: 无法读取此系统上以前注册的服务器的列表。请在“已注册的服务器”窗口中重新注册您的服务器。 ---> Microsoft.SqlServer.Management.Sdk.Sfc.SfcSerializationException: 对 /RegisteredServersStore/ServerGroup/IntegrationServicesServerGroup 的反序列化操作失败。 ---> System.IO.DirectoryNotFoundException: 未能找到路径“C:\Users\Administrator\AppData\Local\Temp\2\6syg1iam.tmp”的一部分。
       在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
       在 System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
       在 System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access)
       在 System.CodeDom.Compiler.TempFileCollection.EnsureTempNameCreated()
       在 System.CodeDom.Compiler.TempFileCollection.AddExtension(String fileExtension, Boolean keepFile)
       在 System.CodeDom.Compiler.TempFileCollection.AddExtension(String fileExtension)
       在 Microsoft.CSharp.CSharpCodeGenerator.FromSourceBatch(CompilerParameters options, String[] sources)
       在 Microsoft.CSharp.CSharpCodeGenerator.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromSourceBatch(CompilerParameters options, String[] sources)
       在 System.CodeDom.Compiler.CodeDomProvider.CompileAssemblyFromSource(CompilerParameters options, String[] sources)
       在 System.Xml.Serialization.Compiler.Compile(Assembly parent, String ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence)
       在 System.Xml.Serialization.TempAssembly.GenerateAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence, XmlSerializerCompilerParameters parameters, Assembly assembly, Hashtable assemblies)
       在 System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location, Evidence evidence)
       在 System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace)
       在 System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)

     解决方法:

    仔细阅读提示信息,发现[未能找到路径“C:\Users\Administrator\AppData\Local\Temp\2\6syg1iam.tmp”的一部分]本路径缺失,在Temp文件夹下,添加“2”文件夹即可。

    更多相关内容
  • redis实现消息队列的几种方式及其优劣

    千次阅读 多人点赞 2022-04-27 18:37:24
    常用的消息队列有,rabbitMq、kafka、RocketMq、ActiveMq等。这些消息队列需要独立安装部署,作为一个中间件来提供服务,虽然有着高性能、高可靠的优点,但是额外部署这些中间件也会增加运维成本,和服务器成本。 本...

    概述

    常用的消息队列有,rabbitMq、kafka、RocketMq、ActiveMq等。这些消息队列需要独立安装部署,作为一个中间件来提供服务,虽然有着高性能、高可靠的优点,但是额外部署这些中间件也会增加运维成本,和服务器成本。

    本篇文章探讨了一下如何使用redis实现消息队列。使用redis无需额外的部署,如果原先就有使用redis的话。此外redis更为轻量也更容易维护。但是redis实现消息队列有多种方案,这些方案有其优点也有其缺点,适用于不同的应用场景。以下从“实时性”、“可靠性”、“功能性”这几个维度做一些对比分析探讨。

    一、理论部分

    “消息队列”是在消息的传输过程中保存消息的容器。
    消息队列常被使用在“流量削峰”、“系统解耦”、“异步调用”这几个方面。
    消息队列主要面对的几个问题是,
    1、并发性能
    2、实时性
    3、如何防止消息丢失,保证可靠性

    从简单的讲,消息队列就是一个“队列”queue,生产者负责发送消息,消息队列存储消息,消费者则负责接收消息。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T6PXcPYP-1651055823390)(https://www.hengyumo.cn/momoclouddisk/file/download?code=202204151015636_image.png)]

    在面对一些亿级流量场景,消息队列届的大哥kafka是如何保证高性能的呢?

    1. Kafka Reactor模型架构
    2. 页缓存技术+磁盘顺序写
    3. ZeroCopy:零拷贝技术
    4. 使用批量消息提升服务端处理能力
      https://www.hengyumo.cn/momoblog/detail/202204162051750

    那使用redis能否获得和kafka一样的高性能呢?答案是一定的。
    redis是如何实现高性能的呢?

    1. IO多路复用
    2. 单线程
    3. 基于内存存储
    4. 高效数据结构
    5. 写时拷贝(CopyOnWrite)
    6. 客户端管道批量命令
    7. 零拷贝技术
      https://www.hengyumo.cn/momoblog/detail/202204162116630

    二、实现消息队列

    2.1 基于list实现

    消息队列的基础结构是队列,而redis正好有相对应的数据结构:list。

    实现方式

    1. 生产者写消息
    lpush mq hello1
    lpush mq hello2
    lpush mq hello3
    lpush mq hello4
    lpush mq hello5
    

    lpush 命令向指定列表的左边推入元素,以上命令模拟了向mq这个消息队列列表中写入五条消息,分别是hello1 ~ hello5。

    同时写入多条也可以跟着多个,如

    lpush mq hello6 hello7
    
    1. 消费者读取消息

    首先,基于list实现的消息队列是可以有效保证实时性的。消费者要如何检测到有新消息推送过来呢?

    • 要么是不停自旋调用llen mq获取队列的长度,如果不为0则读取。或者自旋调用rpop不停读取数据。虽然能保证高实时性,但是这会造成redis的性能浪费和消费者本身的性能浪费,严重时会导致系统崩溃。
    • 定时调用llen mq获取队列的长度。实时性取决于定时任务的频率,如果每100ms一次,则就有100ms的延迟。
    • brpop,brpop可以理解为rpop命令的阻塞升级版,brpop mq 1,会尝试阻塞读取mq 1秒时间,如果1秒内没有消息则会返回nil,如果有消息,会立即返回。

    生产者

    127.0.0.1:6379>
    127.0.0.1:6379> rpush mqb hello
    (integer) 1
    

    消费者

    127.0.0.1:6379> brpop mqb 1
    1) "mqb"
    2) "hello"
    127.0.0.1:6379> brpop mqb 1
    (nil)
    (1.08s)
    

    基于list实现,读取消息可以通过两种方式,一种是rpop,从列表的右边读取并弹出元素。该操作是原子性的,并发下安全。

    rpop mq
    rpop mq
    

    依次弹出的是hello1,hello2,按照先进先出的顺序弹出。

    第二种方式是lrange,使用lrange可以实现消息的批量消费,lrange list start stop 读取list的从start - stop之间的元素。读取之后为了防止重复消费,需要使用ltrim start stop进行清除。因为期间需要进行两个操作,因此不是并发安全的,需要通过分布式锁来保证安全性。此外还存在着事务的问题,如果读取完消息之后进程挂掉,会导致之前已经读取的消息在下次运行时被重复消费。这种方式适用于对消息可靠性要求不高,但是要求处理性能高的情况,如处理大量的日志数据进行分析操作。除了使用ltrim之外也可以使用LREM key count value来删除已经消费的数据。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-isAj1MD5-1651055823391)(https://www.hengyumo.cn/momoclouddisk/file/download?code=202204241041249_image.png)]

    如图所示,假设mq中有7条消息,每次消费3条消息。那么第一条命令lrange mq -3 -1,读取倒数第3到倒数第1之间的所有元素。第二条命令ltrim mq 0 -4,保留未读取的零到倒数第4条消息,把已经读取的消息删除。

    以下演示了在redis-cli中的模拟:

    127.0.0.1:6379> lrange mq -3 -1
    1) "hello3"
    2) "hello2"
    3) "hello1"
    127.0.0.1:6379> ltrim mq 0 -4
    OK
    127.0.0.1:6379> lrange mq 0 -1
    1) "hello7"
    2) "hello6"
    3) "hello5"
    4) "hello4"
    
    1. 多生产者多消费者
    • 多生产者
      基于list的多生产者是没有问题的,多个生产者同时向mq中推送消息,仍然能保证消息有序。

    • 多消费者

      • rpop方式 多消费者下并发同样安全,不会出现消息被重复消费的情况
      • lrange + ltrim 方式 多消费者下并发不安全,需要使用分布式锁保证有序,否则会出现消息被重复消费的问题。同时不保证事务安全性。需要通过额外手段记录读取mq的位置,以保证宕机复位时不会出现消息重复读取的问题。
    1. 发布订阅方式

    发布订阅简单的理解是将一个消息广播给多个消费者,每个消费者针对该消息只消费一次。

    针对发布订阅有两种思路,一种是较为简单的,既然一对一消费可以通过一个list实现,那么一对多消费就使用多个list来一一对应各个消费者:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kWu8BIMc-1651055823391)(https://www.hengyumo.cn/momoclouddisk/file/download?code=202204241058734_image.png)]

    这里只需要维护一个消费者和消息队列名称映射的列表,生产者发送消息时发送给所有的消费者对应的队列。
    消费者读取自己对应的消息队列。

    实现起来简单,但是存在两个问题:

    • 资源浪费,原本只需要一个列表存储,变成了几个消费者就需要几个列表,而且列表的数据都是相同的,这无疑造成了浪费。当数据量不大,消费者不多时可以不顾及这点。
    • 无法保证消息可靠的同步发送到各个队列上。如果生产者写入完mq1之后就宕机了,就好导致只有消费者1接收到了消息,而其它的消费者无法接收到消息,这就会导致数据不一致的情况出现。

    第二种实现方式,就是仍然只维护一个队列,这样使用方法1两个问题就没有了。但是要如何保证各个消费者能消费到数据呢?

    使用rpop肯定不行的,会导致消息丢失,所以还是得用lrange来读取数据。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IEEY0gjI-1651055823392)(https://www.hengyumo.cn/momoclouddisk/file/download?code=202204241117840_image.png)]

    上图演示了实现的思路,

    首先是维护一个读取位置的map,保存每个消息队列读取到的位置。每个消费者读取数据时从自己上一次读取的位置继续读取。读取完成之后更新该位置。

    这种方式也实现了消息应答。可以保证消费者宕机的情况下,下次能回到前次消费的坐标进行消费,以防止消息丢失。

    当然这种方式也存在着问题

    • 消息未被清除,会一直堆积下去。这个可以通过一个定时线程清除已读取的消息并且更新所有消费者读取消息的位置。但是还要保证并发安全性,因此这个定时清除线程还需要加锁。这会造成一部分的性能损失。
    1. 消息应答

    消息应答机制是保证消费者可靠消费消息的有效手段。主要过程就是,消费者拿到数据之后,先进行消费的业务逻辑,消费完成之后回复消息队列一个ACK报文,之后消息队列才将消息移除掉。通过这种方式可以有效防止消费者宕机导致消息丢失的情况。

    在redis可以通过rpoplpush这个命令来实现ACK机制。

    Redis rpoplpush 命令用于移除列表的最后一个元素,并将该元素添加到另一个列表并返回。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gYIXDvP1-1651055823392)(https://www.hengyumo.cn/momoclouddisk/file/download?code=202204241220718_image.png)]

    针对上图的点对点方式的消息队列,在不考虑并发消费的情况下,是可靠的。

    1. brpoplpush mq ack 1 阻塞读取mq的消息,之后写入ack列表
    2. lpop ack 清除ACK最左侧已经消费的数据,模拟推送ack报文操作

    假设这时消费者宕机,完成了步骤1,但是未完成步骤2,那么在ACK队列第一个元素之后就会备份这些未消费的数据。

    再启动一个线程,作为纠错服务。定时读取ACK队列第二个元素及其之后的元素,重新推入MQ,进行消费。这样可以有效的防止消息丢失。

    list方式的消息队列总结

    • 实时性 实时性较好,可以通过brpop方式阻塞获取新消息,有高实时性;或者通过定时任务方式监听队列,存在较低延迟。
    • 可靠性 综合可靠性一般,在点对点的消息推送机制下(lpush + rpop方案)不容易存在消息丢失,可以保证高可靠性。在其它场景可能存在并发安全性问题,但是可以通过加锁解决。存在事务失败问题,但是发生的概率较低。存在消息丢失问题,但是可以自己实现ack机制。
    • 功能性 功能性一般,通过自己的额外扩展可以满足多种不同的消息队列功能,如多对多、发布订阅模式。

    基于list的特点,可以推导出在两种常见场景下的实现方案:

    针对生产者都采用lpush的方式推送数据,

    针对消费者:

    1. 对实时性和可靠性要求高的情况,消费者使用brpop阻塞读取和消费数据
    2. 对实时性和可靠性要求不高的情况,但是推送数据量大,要求处理性能高,消费者使用定时任务+lrange+ltrim方式读取和消费数据

    2.2 基于pub-sub实现

    pub-sub 是redis官方支持的一种发布订阅模式。

    实现方式

    1. 生产者写消息

    首先需要着重注意的是,pub-sub机制和list不同,list是redis的数据结构,redis自身会保证其数据持久化的可靠性,而pub-sub则没有持久化机制,这意味着,如果发生消息时,消费者宕机,那么消息也就丢失了。所以该种方式是不满足可靠性要求的。

    生产者发生消息使用命令 publish channel message的方式,

    例如

    publish mq hello1
    publish mq hello2
    publish mq hello3
    

    在发送消息时没有消费者订阅该频道的话,那么该消息就会被丢弃。

    1. 消费者读取消息

    消费者使用subscribe channel命令来订阅某个频道,其中channel代表频道的名称,执行该命令之后就会阻塞,直到有消息到来。

    例如

    • 消费者监听消息
    127.0.0.1:6379> subscribe mq
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "mq"
    3) (integer) 1
    
    • 在生产者发送消息
    127.0.0.1:6379> publish mq hello1
    (integer) 1
    
    • 消费者监听到新消息
    127.0.0.1:6379> subscribe mq
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "mq"
    3) (integer) 1
    1) "message"
    2) "mq"
    3) "hello1"
    

    此外还可以使用psubscribe channelLike命令来执行通配符匹配,满足名称匹配的频道的消息都会被接收。通过这种方式可以很简单的实现一个消费者订阅多个话题。

    例如

    • 消费者监听消息
    127.0.0.1:6379> psubscribe mq*
    Reading messages... (press Ctrl-C to quit)
    1) "psubscribe"
    2) "mq*"
    3) (integer) 1
    
    • 在生产者发送消息
    127.0.0.1:6379> publish mq1 hello1
    (integer) 1
    127.0.0.1:6379> publish mq2 hello2
    (integer) 1
    
    • 消费者监听到新消息
    127.0.0.1:6379> psubscribe mq*
    Reading messages... (press Ctrl-C to quit)
    1) "psubscribe"
    2) "mq*"
    3) (integer) 1
    1) "pmessage"
    2) "mq*"
    3) "mq1"
    4) "hello1"
    1) "pmessage"
    2) "mq*"
    3) "mq2"
    4) "hello2"
    
    1. 多生产者多消费者

    pub-sub实现多生产者是很简单的,和点对点模式基本没有区别。但是多消费者的情况下,会出现消息被重复消费的情况。

    多生产者

    多个生产者向一个频道写入消息:
    例如

    生产者1:

    
    127.0.0.1:6379> publish mq hello1
    (integer) 1
    
    

    生产者2:

    
    127.0.0.1:6379> publish mq hello2
    (integer) 1
    
    

    多消费者
    假设有一个服务,存在两个实例,作为消费者若使用subscribe它们是独立的两个消费者,但是作为功能而言,它们是同一个服务。如果出现多实例反复消费多次的情况下,数据的一致性就会出现问题。

    如果两个实例都订阅了mq这个频道。那么每个消息都会被重复消费一次。

    那要怎么保证并发消费时不被重复消费呢。pub-sub本身并没有解决方案。也无法判断收到的消息是否已经被消费过。只能绕开pub-sub。

    例如让每个实例都监听不同的频道,生产者采用轮询或者随机负载算法,来将消息写入某一个指定的频道,而指定的某个频道,只有一个消费者来消费它,依靠这样的流程来实现并发消费。这种方案性能有较高的保障,但是存在一旦某个实例宕机,某个频道的消息全部都无法被消费的情况。

    或者采用一个分布式锁的方式来调度这样的竞争访问。例如实例A读取到了消息,那么它申请一个锁,在这个锁有效期内,它可以任意的消费频道的消息。而其它竞争对手尝试获取锁失败之后,则不允许消费数据,虽然也接收到了消息,但是直接丢弃,不做处理。直到这个分布式锁释放被另一个实例占用。这种方式实现起来相对简单,但是存在着性能上的极大浪费。严重情况可能还不如单实例监听,但是多实例方案至少避免了单实例挂掉的情况下,所有消息都无法被消费的情况。

    1. 发布订阅方式

    pub-sub原生就是发布订阅模式的实现,因此不再叙述,可以参考上述内容。

    1. 消息应答

    以下通过引入一个纠错消费者的概念来实现ack机制。同时保证消息消费的可靠性。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qdXPncKe-1651055823393)(https://www.hengyumo.cn/momoclouddisk/file/download?code=202204241531189_image.png)]

    针对每一条消息,生成一个唯一不重复的ID来标识消息。纠错消费者接受到消息之后将其存入本地持久化map中,此处可以使用redis或者数据库,考虑到性能采用redis zset的方式会更好一些。

    例如 message Msg27839:hello,Msg27839是该条消息的唯一标识。hello是实际的消息内容。

    纠错消费者获取到该消息之后,先将其存入redis中,分别存入三个key中,一个key是Msg27839,value是hello,用来存储原始的消息,设置时间ttl为1min。一个key是zset ack1:Msg27839,score是当前时间戳+30s的时间,一个key是zset ack2:Msg27839,score也是当前时间戳+30s的时间,分别代表ack1和ack2两个频道的ack接收确认,利用zset的有序性,可以很轻松的一次性读取出所有过期未收到ack报文的消息

    当消费者1消费完消息之后,向ack1频道发送消息,消息内容为消息ID,纠错消费者监听到消息之后,删除zset中的ack1:Msg27839。此时假设消费者2宕机,未能成功消费消息并且发送ack消息到ack2频道。

    纠错服务定时每半分钟读取一次zset,从zset取出分数小于当前时间戳的所有消息,将其重新写入到bak1或者bak2频道中。此时ack3:Msg27839消息未接收到ack报文,因此重新将其推送到频道bak2中进行二次消费,同时重新设置Msg27839这个存储原始消息的key的过期时间为1min。

    此处的30s读取一次zset,我们认为该消费正常被处理的时间是30s如果超过30s未返回ack则认为是失败

    此处的原始消息存储1min时间,是让其能自动过期,释放空间,不用手动删除。1min时间是30s的两倍,是为了保证纠错服务进行回写bak频道时消息仍然能被读取到。

    我们假设一种场景,如果消费者1和消费者2全部宕机的情况下。那么消息也会通过纠错服务一直持久化到redis中,不会导致消息丢失。一旦两个消费者恢复可用,之前的历史消息就能被纠错服务通过定时任务的方式推送给两个消费者,消息没有丢失。

    基于以上的实现逻辑我们总能保证消息都会被所有消费者消费到。并且也间接实现了pub-sub的持久化。

    pub-sub方式的消息队列总结

    • 实时性 实时性极好,实现的消息推送机制本身就是高实时性的。
    • 可靠性 可靠性较差。一旦消费者宕机消息就会直接被丢弃。
    • 功能性 功能性一般,实现简单的发布订阅还好,但是为了满足一些高可用性就需要增加很多额外的操作。

    基于pub-sub的特点,可以推导出在其常用场景:

    不在意消息丢失,不在意消息接收可靠性,需要发布订阅功能,需要高实时性的场景。
    这种场景一般常见于日志推送。

    2.3 基于redis5的stream实现

    https://www.runoob.com/redis/redis-stream.html

    Redis Stream 是 Redis 5.0 版本新增加的数据结构。

    Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。

    简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。

    而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

    Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uijc8w1d-1651055823393)(https://www.hengyumo.cn/momoclouddisk/file/download?code=202204251319871_image.png)]

    其实redis stream是针对list的一个加强,底层的数据结构也是list。其实现原理和前文2.1介绍的list实现发布订阅类似,都是通过一个标志位记录当前consumer消费者访问的位置。

    对于一个stream可以对应多个consumer group(消费者组)。一个消费者组可以包含多个消费者。

    last_deliverd_id记录了该消费者组访问到list的位置,也就是游标。下次读取消息时从该位置继续往前读取。需要注意的是,记录的是消费者组的位置,消费者组中任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。

    pending_ids 记录了消费者(Consumer)的状态变量,作用是维护消费者的未确认的 id。 pending_ids 记录了当前已经被客户端读取的消息,但是还没有 ack (Acknowledge character:确认字符)。通过这个实现了消息应答机制,保证了消息推送的可靠性。

    stream的部分命令和list一致,只是将L替换成为了X作为特殊标识,例如:

    XADD - 添加消息到末尾
    XTRIM - 对流进行修剪,限制长度
    XLEN - 获取流包含的元素数量,即消息长度
    XRANGE - 获取消息列表,会自动过滤已经删除的消息
    

    以上命令在list中都是存在的。

    而以下命令是stream特有的:

    XDEL - 删除消息
    XREVRANGE - 反向获取消息列表,ID 从大到小
    XREAD - 以阻塞或非阻塞方式获取消息列表
    
    XGROUP CREATE - 创建消费者组
    XREADGROUP GROUP - 读取消费者组中的消息
    XACK - 将消息标记为"已处理"
    XGROUP SETID - 为消费者组设置新的最后递送消息ID
    XGROUP DELCONSUMER - 删除消费者
    XGROUP DESTROY - 删除消费者组
    XPENDING - 显示待处理消息的相关信息
    XCLAIM - 转移消息的归属权
    XINFO - 查看流和消费者组的相关信息;
    XINFO GROUPS - 打印消费者组的信息;
    XINFO STREAM - 打印流信息
    
    

    使用stream之前需要保证当前的redis版本>5:

    ./redis-server -v
    Redis server v=5.0.5 sha=00000000:0 malloc=jemalloc-5.1.0 bits=64 build=d448d45b28029e7
    
    

    需要注意的是windows的redis已经停止更新了,目前只到3:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fD7QvqR7-1651055823393)(https://www.hengyumo.cn/momoclouddisk/file/download?code=202204251345256_image.png)]

    所以需要使用linux版本。

    实现方式

    1. 生产者写消息

    使用XADD key ID field value [field value ...]来创建并写消息:

    • key :队列名称,如果不存在就创建
    • ID :消息 id,我们使用 * 表示由 redis 生成,可以自定义,但是要自己保证递增性。
    • field value : 记录。
    127.0.0.1:6379> xadd mq * msg hello
    "1650865623927-0"
    127.0.0.1:6379> xadd mq * msg2 hello2 msg3 hello3
    "1650865654238-0"
    

    查看信息:

    # 查看长度
    127.0.0.1:6379> xlen mq
    (integer) 2
    
    # 查看stream信息
    127.0.0.1:6379> xinfo stream mq
     1) "length"
     2) (integer) 2
     3) "radix-tree-keys"
     4) (integer) 1
     5) "radix-tree-nodes"
     6) (integer) 2
     7) "groups"
     8) (integer) 0
     9) "last-generated-id"
    10) "1650865654238-0"
    11) "first-entry"
    12) 1) "1650865623927-0"
        2) 1) "msg"
           2) "hello"
    13) "last-entry"
    14) 1) "1650865654238-0"
        2) 1) "msg2"
           2) "hello2"
           3) "msg3"
           4) "hello3"
    
    # 查看数据 XRANGE key start end [COUNT count]
    127.0.0.1:6379> xrange mq 1650865623927-0 1650865654238-0
    1) 1) "1650865623927-0"
       2) 1) "msg"
          2) "hello"
    2) 1) "1650865654238-0"
       2) 1) "msg2"
          2) "hello2"
          3) "msg3"
          4) "hello3"
    
    # 使用- + 代表开始到结尾
    127.0.0.1:6379> xrange mq - +
    1) 1) "1650865623927-0"
       2) 1) "msg"
          2) "hello"
    2) 1) "1650865654238-0"
       2) 1) "msg2"
          2) "hello2"
          3) "msg3"
          4) "hello3"
    

    上述已经往stream中写入了两条数据。

    还可以使用 XTRIM 对流进行修剪,限制长度, 语法格式:

    XTRIM key MAXLEN [~] count

    • key :队列名称
    • MAXLEN :长度
    • count :数量****

    使用 XDEL 删除消息,语法格式:

    XDEL key ID [ID ...]

    • key:队列名称
    • ID :消息 ID

    使用 XREVRANGE 逆序获取消息列表,会自动过滤已经删除的消息 ,语法格式:

    XREVRANGE key end start [COUNT count]

    • key :队列名
    • end :结束值, + 表示最大值
    • start :开始值, - 表示最小值
    • count :数量

    XREAD
    使用 XREAD 以阻塞或非阻塞方式获取消息列表 ,语法格式:

    XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]

    • count :数量
    • milliseconds :可选,阻塞毫秒数,没有设置就是非阻塞模式
    • key :队列名
    • id :消息 ID 该ID代表从此处开始往后读,读取大于该ID的数据,不包含该ID的数据

    例如

    # 读取第一条数据
    127.0.0.1:6379> xread count 1 block 1000 streams mq 0-0
    1) 1) "mq"
       2) 1) 1) "1650865623927-0"
             2) 1) "msg"
                2) "hello"
    
    # 读取1650865623927-0后一条数据
    127.0.0.1:6379> xread count 1 block 1000 streams mq 1650865623927-0
    1) 1) "mq"
       2) 1) 1) "1650865654238-0"
             2) 1) "msg2"
                2) "hello2"
                3) "msg3"
                4) "hello3"
    

    1. 消费者读取消息

    创建消费者组

    XGROUP [CREATE key groupname id-or-$] [SETID key groupname id-or-$] [DESTROY key groupname] [DELCONSUMER key groupname consumername]

    • key :队列名称,如果不存在就创建
    • groupname :组名。
    • id or $ : id代表从该ID之后开始消费。$表示从尾部开始消费,只接受新消息,当前 Stream 消息会全部忽略。
    # 创建了一个名为c的消费者组,从头部开始消费mq
    127.0.0.1:6379> xgroup create mq c 0-0
    OK
    
    

    创建消费者并消费数据

    XREADGROUP GROUP
    使用 XREADGROUP GROUP 读取消费组中的消息,语法格式:

    XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] ID [ID ...]

    • group :消费组名
    • consumer :消费者名,没有会自动创建。
    • count : 读取数量。
    • milliseconds : 阻塞毫秒数。
    • key : 队列名。
    • ID : 消息 ID,> 代表从头部开始。
    # 为消费者组c创建消费者c1并从mq读取数据,从头部开始读取
    127.0.0.1:6379> xreadgroup group c c1 streams mq >
    1) 1) "mq"
       2) 1) 1) "1650865623927-0"
             2) 1) "msg"
                2) "hello"
          2) 1) "1650865654238-0"
             2) 1) "msg2"
                2) "hello2"
                3) "msg3"
                4) "hello3"
    
    # 读取1个、阻塞10s,从1650865623927-0之后读取
    127.0.0.1:6379> xreadgroup group c c1 count 1 block 10000 streams mq 1650865623927-0
    1) 1) "mq"
       2) 1) 1) "1650865654238-0"
             2) 1) "msg2"
                2) "hello2"
                3) "msg3"
                4) "hello3"
    

    我们使用ack命令标识stream的两条数据为已经消费完成

    127.0.0.1:6379> xack mq c 1650865623927-0 1650865654238-0
    (integer) 2
    

    之后再使用xreadgroup读取数据,因为此时队列的数据都已经消费过,所以会阻塞10s等待新的消息推送过来

    
    127.0.0.1:6379>  xreadgroup group c c1 count 1 block 10000 streams mq >
    (nil)
    (11.15s)
    

    写入一条新的消息:

    127.0.0.1:6379> xadd mq * msg hi
    "1650868048238-0"
    

    消费者成功接收到消息:

    127.0.0.1:6379>  xreadgroup group c c1 count 1 block 10000 streams mq >
    1) 1) "mq"
       2) 1) 1) "1650868048238-0"
             2) 1) "msg"
                2) "hi"
    (3.62s)
    

    查看消费者状态:

    127.0.0.1:6379> xinfo groups mq
    1) 1) "name"
       2) "c"
       3) "consumers"
       4) (integer) 1
       5) "pending"
       6) (integer) 2
       7) "last-delivered-id"
       8) "1650868048238-0"
    
    127.0.0.1:6379> xinfo consumers mq c
    1) 1) "name"
       2) "c1"
       3) "pending"
       4) (integer) 2
       5) "idle"
       6) (integer) 270305
    

    mq有一个消费者组c,c有一个消费者c1,c当前读取到1650868048238-0,可以看到该位置就是队列的末尾了。但是还有两个pending的,代表有两条消息没有收到ACK,而270305代表其等待的时间ms。

    127.0.0.1:6379> xrange mq - +
    1) 1) "1650865623927-0"
       2) 1) "msg"
          2) "hello"
    2) 1) "1650865654238-0"
       2) 1) "msg2"
          2) "hello2"
          3) "msg3"
          4) "hello3"
    3) 1) "1650867786477-0"
       2) 1) "msg"
          2) "hi"
    4) 1) "1650867796123-0"
       2) 1) "msg"
          2) "hi"
    5) 1) "1650867834732-0"
       2) 1) "msg"
          2) "hi"
    6) 1) "1650868048238-0"
       2) 1) "msg"
          2) "hi"
    

    使用xpending查看这两条数据:
    xpendign key groupName [start end count] [consumerName]

    127.0.0.1:6379> xpending mq c
    1) (integer) 2
    2) "1650867834732-0"
    3) "1650868048238-0"
    4) 1) 1) "c1"
          2) "2"
    

    原来是"1650867834732-0","1650868048238-0"没有被成功消费掉。

    发送ack,再查看已经没有pending的消息了。

    127.0.0.1:6379> xack mq c 1650867834732-0 1650868048238-0
    (integer) 2
    127.0.0.1:6379> xpending mq c
    1) (integer) 0
    2) (nil)
    3) (nil)
    4) (nil)
    
    

    这些pending的数据,同个消费者组下的其它消费者也是读取不到的。

    redis会对这些pending的消息做数据恢复吗?答案是不会,需要手动去处理它,使用xdel将其删除,然后重新写入mq。需要注意的是xdel不会删除pending的数据,需要在重新写入完成之后将其ack。

    例如当前有一条未ack的消息:

    127.0.0.1:6379> xpending mq c - + 10 c1
    1) 1) "1650868714168-0"
       2) "c1"
       3) (integer) 156886
       4) (integer) 1
    

    我们可以这样操作,将其删除,重新写入mq,然后ack。消费者再次读取时就没有问题了。

    127.0.0.1:6379> xdel mq 1650868714168-0
    (integer) 1
    127.0.0.1:6379> xpending mq c
    1) (integer) 1
    2) "1650868714168-0"
    3) "1650868714168-0"
    4) 1) 1) "c1"
          2) "1"
    127.0.0.1:6379> xadd mq * msg hi
    "1650869436235-0"
    
    127.0.0.1:6379> xack mq c 1650868714168-0
    (integer) 1
    127.0.0.1:6379> xpending mq c
    1) (integer) 0
    2) (nil)
    3) (nil)
    4) (nil)
    127.0.0.1:6379>  xreadgroup group c c2 count 1 block 10000 streams mq >
    1) 1) "mq"
       2) 1) 1) "1650869436235-0"
             2) 1) "msg"
                2) "hi"
    127.0.0.1:6379> xack mq c 1650869436235-0
    (integer) 1
    127.0.0.1:6379> xpending mq c
    1) (integer) 0
    2) (nil)
    3) (nil)
    4) (nil)
    

    除了删除重新写入的场景之外,还可以使用xclaim来做消息转移。xclaim可以将消息转移到同消费者组的另一个消费者的pending队列中,同时其还会返回消息内容。如果某个消费者故障,转移到另一个消费者受理是一个不错的方式。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aSKnxlGE-1651055823393)(https://www.hengyumo.cn/momoclouddisk/file/download?code=202204251524928_image.png)]

    解释:XCLAIM命令用于进行消息转移,当某个等待队列中的消息长时间没有被处理(没有ACK)的时候,可以用XCLAIM命令将其转移到其他消费者的等待列表中。

    key:表示消息队列的名称。
    group:表示消费者组名称。
    consumer:表示消费者名称。
    min-idle-time:表示消息空闲时长(表示消息已经读取,但还未处理)。
    ID [ID …]:可选参数,表示要转移的消息的消息ID,可传入多个消息ID。
    [IDLE ms]:可选参数,设置消息空闲时间(上一次读取消息的时间),如果未指定,这假定IDLE为0,即每次转移消息之后重置消息空闲时间。因为如果空闲时间一直累加的话,消息会一直转移。
    [TIME ms-unix-time]:可选参数,与IDLE参数相同,只是它将空闲时间设置为特定的Unix时间(以毫秒为单位),而不是相对的毫秒量。这对于重写生成XCLAIM命令的AOF文件非常有用。
    [RETRYCOUNT count]:可选参数,设置重试计数器的值,每次消息被读取时,该计数器都会递增。一般XCLAIM命令不需要修改重试计数器的值。
    [FORCE]:可选参数,即使指定要转移的消息的消息ID在其他等待列表中不存在,也强制将该消息ID加入到执行消费者的等待列表中。
    [JUSTID]:可选参数,仅返回要转移消息的消息ID,使用此参数意味着重试计数器不会递增。

    1. 多生产者多消费者

    多生产者
    只要都使用 xadd命令往同一个stream写入即可。

    多消费者
    创建一个消费者组,将多个消费者都包含进该消费者组中,即可。

    1. 发布订阅方式
      实现多个消费者组监听同一个stream即可。

    2. 消息应答
      使用strean的原生的ack机制即可。不过需要注意,对应pending的数据需要安排一个线程定时去处理和恢复。

    stream方式的消息队列总结

    • 实时性 实时性好,可以通过block方式阻塞获取新消息,有高实时性;
    • 可靠性 可靠性好,redis的自带的持久化机制可以防止消息丢失,但是相比kafka的磁盘写入还是略不可靠。自带的ack机制可以满足消息应答实现,防止消息丢失。但是需要注意对于死信息积压在pending区的数据需要定时去处理回收。此外,积压的消息会一直保存在stream中,哪怕已经ack过,还需要额外的一个线程定时将已经读取完的消息删除。
    • 功能性 功能性好,可以轻松实现多种不同的消息队列功能,如多对多、发布订阅模式。

    基于stream的特点,可以推导出在其常用场景:

    大部分使用消息队列的场景都可以使用stream替代。基于redis的高性能和使用内存的机制使得其的性能优于大部分消息队列。在小规模场景会有更出色的表现。但是针对大流量的场景不推荐使用stream,毕竟内存的大小是有限的,这也是所有redis实现的消息队列的局限之处。


    END

    写文不易,这篇文章断断续续写了一周时间,如果对您有帮助不如点个赞支持一下~

    []~( ̄▽ ̄)~*
    

    关注我获取golang、架构相关博文更新。
    同时欢迎您访问我的博客www.hengyumo.cn阅读第一手博客。

    展开全文
  • python判断字符串以什么结尾的实例方法函数:endswith()作用:判断字符串是否以指定字符或子字符串结尾,常用于判断文件类型。相关函数:判断字符串开头 startswith()函数说明:语法:string.endswith(str, beg=[0,...

    python判断字符串以什么结尾的实例方法

    函数:endswith()

    作用:判断字符串是否以指定字符或子字符串结尾,常用于判断文件类型。

    相关函数:判断字符串开头 startswith()

    函数说明:

    语法:

    string.endswith(str, beg=[0,end=len(string)])

    string[beg:end].endswith(str)

    参数说明:

    string: 被检测的字符串

    str:      指定的字符或者子字符串(可以使用元组,会逐一匹配)

    beg:    设置字符串检测的起始位置(可选,从左数起)

    end:    设置字符串检测的结束位置(可选,从左数起)

    如果存在参数 beg 和 end,则在指定范围内检查,否则在整个字符串中检查。

    返回值:

    如果检测到字符串,则返回True,否则返回False。

    解析:如果字符串string是以str结束,则返回True,否则返回False。

    例子:

    在python编辑器汇总新建一个data.py。

    写上自己的注释。

    然后新建一个变量testname。

    利用endswith()来判断字符串是不是以"ar"结尾。

    将结果打印出来。

    选择"run"->"run"。

    运行该程序,如果是,就会返回true。

    以上就是python判断字符串以什么结尾的实例方法的详细内容,更多关于python如何判断字符串以什么结尾的资料请关注我们其它相关文章!

    时间: 2020-09-16

    算法1 1.分小数和整数:如果小数点个数为1,则可能是小数.如小数点个数为0,则可能是整数.小数点个数非0也非1,那么就不是数字. 2.如果是小数,再分正数和负数的情况:如果首位为负号,则可能是负小数.如果首位不为负号,则可能是正小数. 1)如果首位为负号,则去掉负号. 2)如果首位不为负号:或者是首位为负号,去掉首位负号之后.则判断是否为是否为".",如果是,那么就不是数字,如果不是,就去掉"." 3)再判断剩下字符是否都在"0123456789&quo

    这学期在学习编译原理,最近的上机作业就是做一个简单的词法分析器,在做的过程中,突然有个需求就是判断一个字符串是否为合法的标示符,因为我是用python语言做的,做的是Python的词法分析器,于是下面分享以下怎样判断一个字符串是合法的标示符. 首先,我们来熟悉以下python标示符的定义是什么? 定义:以字母或下划线开始的,由字母,数字或下划线组成,但是不能是python的保留字. 又有疑问了,python有哪些保留字,分别是什么? # python2.x import keyword prin

    判断python中的一个字符串是否为空,可以使用如下方法 1.使用字符串长度判断 len(s) ==0 则字符串为空 #!/user/local/python/bin/python # coding=utf-8 test1 = '' if len(test1) == 0: print '字符串TEST1为空串' else: print '字符串TEST1不是空串,TEST1:' + test1 2.isspace判断是否字符串全部是空格 Python isspace() 方法检测字符串是否只由空

    判断是否xx开始 使用startswith 示例代码: String = "12345 上山打老虎" if str(String).startswith('1'): #判断String是否以"虎"结尾 print("有老虎") else: print("没老虎") 执行结果: 有老虎 判断是否xx结尾 使用endswith 示例代码1: String = "12345 上山打老虎" if str(Strin

    1. 使用 in 和 not in in 和 not in 在 Python 中是很常用的关键字,我们将它们归类为 成员运算符. 使用这两个成员运算符,可以很让我们很直观清晰的判断一个对象是否在另一个对象中,示例如下: >>> "llo" in "hello, python" True >>> >>> "lol" in "hello, python" False 2. 使用

    model中compile值可以根据需要更改,满足不同的检测需求 #判断一段文本中是否包含简体中文 import re zhmodel = re.compile(u'[\u4e00-\u9fa5]') #检查中文 #zhmodel = re.compile(u'[^\u4e00-\u9fa5]') #检查非中文 contents = u'(2014)深南法民二初字第280号' match = zhmodel.search(contents) if match: print(contents) e

    本文实例讲述了Python实现判断字符串中包含某个字符的判断函数.分享给大家供大家参考,具体如下: #coding=utf8 #参数包含两个: #containVar:查找包含的字符 #stringVar:所要查找的字符串 def containVarInString(containVar,stringVar): try: if isinstance(stringVar, str): if stringVar.find(containVar): return True else: return

    本文实例讲述了Python判断文本中消息重复次数的方法.分享给大家供大家参考,具体如下: #coding:gbk ''' Created on 2012-2-3 从文件中读取文本,并判断文本中形如"message0"."message123"这样的消息有多少条是重复的 @author: Administrator ''' import re if __name__ == '__main__': pattern = u"(message((\d)+))&qu

    一.判断字符串中包含中文字符的方法 遍历数组,对每个字节使用string.byte(),发现有大于127的,就是汉字,可以参照下面的代码. 二.计算字符串宽度函数 复制代码 代码如下: -- 计算字符串宽度   local str = "Jimmy: 你好,世界!" local fontSize = 20 local lenInByte = #str local width = 0   for i=1,lenInByte do     local curByte = string.by

    JS判断字符串变量是否含有某个字串的实现方法 varCts = "bblText"; if(Cts.indexOf("Text") > 0 ){ alert('Cts中包含Text字符串'); } indexOf用法: 返回 String 对象内第一次出现子字符串的字符位置. strObj.indexOf(subString[, startIndex]) 参数 strObj 必选项.String 对象或文字. subString 必选项.要在 String 对

    Java 判断字符串中是否包含中文的实例详解 Java判断一个字符串是否有中文是利用Unicode编码来判断,因为中文的编码区间为:0x4e00--0x9fbb, 不过通用区间来判断中文也不非常精确,因为有些中文的标点符号利用区间判断会得到错误的结果.而且利用区间判断中文效率也并不高,例如:str.substring(i, i + 1).matches("[\\一-\\?]+"),就需要遍历整个字符串,如果字符串太长效率非常低,而且判断标点还会错误.这里提高 一个高效准确的判断方法,使

    在实际工作中,有时候需要对判断字符串是否为合法的json格式 解决方法使用json.loads,这样更加符合'Pythonic'写法 代码示例: Python import json def is_json(myjson): try: json_object = json.loads(myjson) except ValueError, e: return False return True 运行代码编辑模式复制折叠 输出结果: Python print is_json("{}") #

    1.背景 最近的项目中,再次踩到Python字符串处理的坑,决定把此次解决方案记录一下,以勿踩坑. 2.遇到坑 原本字符串:大坪英利国际8号楼88-88号重庆汉乔科技有限公司大坪英利国际8号楼 去除最左边的字符串:大坪英利国际8号楼 预期结果:88-88号重庆汉乔科技有限公司大坪英利国际8号楼 自然而然,第一个想到的就是lstrip()函数. Python中lstrip() 方法用于截掉字符串左边的空格或指定字符. 但实际上结果: lstrip: -88号重庆汉乔科技有限公司大坪英利国际8号楼

    问题 你想将HTML或者XML实体如 &entity; 或 code; 替换为对应的文本. 再者,你需要转换文本中特定的字符(比如, 或 &). 解决方案 如果你想替换文本字符串中的 '' ,使用 html.escape() 函数可以很容易的完成.比如: >>> s = 'Elements are written as "text".' >&

    展开全文
  • Python-字符串开头或结尾匹配

    千次阅读 2021-01-29 14:15:33
    startswith() 和 endswith() 方法提供了一个非常方便的方式去做字符串开头和结尾的检查。1、查看指定目录下的所有文件名>>> import os>>> filenames = os.listdir('I:\PythonTest')>>> ...

    startswith() 和 endswith() 方法提供了一个非常方便的方式去做字符串开头和结尾的检查。

    1、查看指定目录下的所有文件名

    >>> import os

    >>> filenames = os.listdir('I:\PythonTest')

    >>> filenames

    ['111.csv', '111.xlsx', '111.xml', '123.txt', '123.xlsx', '123123.xml', '123123.xml.bak', '1234.txt', '222.xml', 'book.xml', 'book.xml.bak', 'excelWrite.csv', 'excelWrite.xlsx', 'Koala.jpg', 'movie.xml', 'movie.xml.bak', 'movies.xml', 'receive.txt', 'user.xml', 'user.xml.bak', '新建文件夹']

    2、列出.txt文件名

    >>> for i in filenames:

    if i.endswith('.txt'):

    print(i)

    123.txt

    1234.txt

    receive.txt

    另外一种写法:

    >>> i for i in filenames if i.endswith('.txt')

    SyntaxError: invalid syntax

    >>> [i for i in filenames if i.endswith('.txt')] #结果返回一个list[]

    ['123.txt', '1234.txt', 'receive.txt']

    >>> a = [i for i in filenames if i.endswith('.txt')]

    >>> print(a)

    ['123.txt', '1234.txt', 'receive.txt']

    3、同时列出.txt和.xml文件

    如果你想检查多种匹配可能,只需要将所有的匹配项放入到一个元组(‘a’,’b’,’c’)中去, 然后传给startswith() 或者 endswith() 方法

    >>> for i in filenames:

    if i.endswith(('.txt','.xml')):

    print(i)

    111.xml

    123.txt

    123123.xml

    1234.txt

    222.xml

    book.xml

    movie.xml

    movies.xml

    receive.txt

    user.xml

    >>> [i for i in filenames if i.endswith(('.txt','.xml'))]

    ['111.xml', '123.txt', '123123.xml', '1234.txt', '222.xml', 'book.xml', 'movie.xml', 'movies.xml', 'receive.txt', 'user.xml']

    4、列出开头为book和1的文件名

    >>> [i for i in filenames if i.startswith(('book',''))]

    ['111.csv', '111.xlsx', '111.xml', '123.txt', '123.xlsx', '123123.xml', '123123.xml.bak', '1234.txt', 'book.xml', 'book.xml.bak']

    5、查看是否存在xml的文件

    检查某个文件夹中是否存在指定的文件类型:

    if any(name.endswith(('.c', '.h')) for name in listdir(dirname)):

    >>> any(name.endswith('.xml') for name in filenames)

    True

    Python: 字符串开头或结尾匹配str.startswith(),str.endswith()

    问题 需要通过指定的文本模式去检查字符串的开头或者结尾,比如文件名后缀,URLScheme 等等. 解决方案 1.检查字符串开头或结尾的一个简单方法是使用str.startswith() 或者是str ...

    python文本 字符串开头或者结尾匹配

    python文本 字符串开头或者结尾匹配 场景: 字符串开头或者结尾匹配,一般是使用在匹配文件类型或者url 一般使用startwith或者endwith >>> a='http:/ ...

    原生jS之-去掉字符串开头和结尾的空字符

    怎么解决这个问题?? 思路就是我们利用正则匹配到所谓的空格,然后替换为空字符,我们要用到的是str的replace API 代码如下:

    【trim()】去掉字符串开头和结尾的空格,防止不必要的空格导致的错误。

    去掉字符串开头和结尾的空格,防止不必要的空格导致的错误. public static void main(String arg[]){ String a=" abc"; Strin ...

    python_如何判断字符串a以某个字符串开头或结尾?

    案例: 某文件系统目录下有一系列文件: 1.c 2.py 3.java 4.sh 5.cpp ...... 编写一个程序,给其中所有的.sh文件和.py文件加上可执行权限 如何解决这个问题? 1. 先 ...

    Python-判断字符串是否以某个字符串开头或结尾?

    案例: 某文件系统目录下有一系列文件: 1.c 2.py 3.java 4.sh 5.cpp ...... 编写一个程序,给其中所有的.sh文件和.py文件加上可执行权限 如何解决这个问题? 1. 先 ...

    Python: 去掉字符串开头、结尾或者中间不想要的字符

    ①Strip()方法用于删除开始或结尾的字符.lstrip()|rstirp()分别从左右执行删除操作.默认情况下会删除空白或者换行符,也可以指定其他字符. ②如果想处理中间的空格,需要求助其他技术 ...

    python 字符串的特性

    #######str字符串#####str字符判断大小写  url1 = 'http://www.cctv.com'  url2 = 'file:///mnt'  print url1.startsw ...

    python 字符串探讨

    本文内容基于python3 几乎所有有用的程序都会涉及到某些文本处理,不管是解析数据还是产生输出.字符串的学习是重点中的重点,这一节将重点关注文本的操作处理,比如提取字符串,搜索,替换以及解析等.大部 ...

    随机推荐

    Android之自定义View的实现

    对于学习Android开发的小童鞋对于自定义View一定不会陌生,相信大家对它是又爱又恨,爱它可以跟随我们的心意设计出漂亮的效果:恨它想要完全流畅掌握,需要一定的功夫.对于初学者来说确实很不容易,网上 ...

    李洪强iOS经典面试题154- 通知与推送

    李洪强iOS经典面试题154- 通知与推送   通知与推送 本地通知和远程推送通知对基本概念和用法? image 本地通知和远程推送通知都可以向不在前台运行的应用发送消息,这种消息既可能是即将发生的事 ...

    【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单

    一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两 ...

    MySQL 拷贝数据库表方式备份,还原后提示 table xxx '' doesn`t exist

    MySQL很强大,支持直接拷贝数据库文件快速备份,那数据库文件在哪里呢? 打开MySQL的配置文件 my.ini,找到 datadir 节点,如 datadir="D:/Program Fi ...

    转:JQuery选择器

    选择器是jQuery最基础的东西,本文中列举的选择器基本上囊括了所有的jQuery选择器,也许各位通过这篇文章能够加深对jQuery选择器的理 解,它们本身用法就非常简单,我更希望的是它能够提升个人编 ...

    mysql数据库中查询时间

    项目中要对数据按时间处理,在数据库中,时间处理的格式如 2014-12-09 06:30:17 时间查询出来如下所示: 现在要查询具体有哪天的数据,应用substring函数,SQL如下: ) as ...

    如何离线安装Visual Studio 2017

    1. 官方下载在线安装文件 vs_community.exe https://www.visualstudio.com/zh-hans/thank-you-downloading-visual-stu ...

    实现基于LVS负载均衡集群的电商网站架构

    背景 上一期我们搭建了小米网站,随着业务的发展,网站的访问量越来越大,网站访问量已经从原来的1000QPS,变为3000QPS,网站已经不堪重负,响应缓慢,面对此场景,单纯靠单台LNMP的架构已经无法 ...

    java中类的加载过程和对象的创建过程

    1.类加载过程 首先,jvm在执行时,遇到一个新的类,会先去内存的方法区中去寻找该类的.class文件,如果找到了就直接运行,如果没有找到,则会去硬盘中去寻找该类的.class文件,并将该类文件加载到 ...

    spring基于XML的声明式事务控制

    展开全文
  • 请参见此消息结尾。 ************** 异常文本 ************** System.NullReferenceException: 未将对象引用设置到对象的实例。 在 ZuHaoFrm.FrmMain.Form1_Load(Object sender, EventArgs e) 在 Sy
  • Java中字符串字符的结尾 - java

    千次阅读 2021-03-18 09:42:36
    - java 我从服务器收到此消息,我不明白T和Z的含义,2012-08-24T09:59:59Z将此字符串转换为Date对象的正确SimpleDateFormat模式是什么? java大神给出的解决方案 这是ISO 8601标准。您可以使用SimpleDateFormat ...
  • 微信发送消息接口

    千次阅读 2021-05-16 21:27:08
    1.模版中参数内容必须以".DATA"结尾,否则视为保留字; 2.模版保留符号"{{ }}" 具体调用方法 第一步:获取模版ID 通过在模版消息功能的模版库中使用需要的模版,可以获得模版ID。 第二步:请求接口 请注意,URL置空,...
  • 注册x有关调用实时(JIT)调试而不是此对话框的详细信息,请参见此消息结尾。************** 异常文本 **************System.UnauthorizedAccessException: 对注册表项“HKEY_LOCAL_MACHINE\SOFTWARE\ERA”的...
  • 2.在msg文件夹中定义创建消息obstacleMsg.msg(一定要以”.msg”结尾),并定义消息类型. int32[4] data int32[4] data2 int32[4] data3 3.添加编译支持(如果使用RoboWare Studio编写ROS代码时,以下依赖项可能已经被...
  • 深入python3

    2018-05-17 08:22:58
    深入python3
  • 最近在整公司的QQ机器人开发,我们开发用到的是酷Q,用到的开发工具则是JCQ,然后因为对于图片或者文件消息等,接收到的字符串形如以下: [CQ:image,file=50CB70BF5232E82C5E0D73184FAAE3EB.jpg]广东省方法[CQ:...
  • 话题消息是以.msg结尾的文件,是一个用于描述ROS话题信息简单文本文件,用于生成不同语言消息的源代码。 msg文件一般存放在package下msg文件夹下,其数据类型可以是: int8, int16, int32, int64 (unit*) float32, ...
  • 大家好,我是Leo。 这是开端的第三次循环了。当前正在正处于RocketMQ基础原理。 3万字聊聊什么是RocketMQ(一) 4万字聊聊阿里二面,保证你看不完 ...这个时候我们就要保证事务消息。要不全部成功,要不
  • 文件为test.c grep -E ^"p" test.c #打印以p为开头的行 grep -E "p"$ test.c #打印以p为结尾的行 -E 表示把 ^"p" "p"$当作正则表达式
  • 当socket接收到数据后,会根据buffer的大小一点一点的接收数据,比如: ...消息结尾标记接收消息时判断结尾标记当本次buffer中没有结尾标记时怎么处理我把写好的核心算法贴出来: 代码如下:StringBuilder sb = new S
  • 微信公众号开发之消息模板

    千次阅读 热门讨论 2018-07-06 09:22:29
    微信公众号开发之消息模板 这个消息模板是以订阅号进行模板配置的,如果是认证号就更加简单了,不用自己配置!!! 只需要知道模板ID,和模板的样式就行。 微信公众号发送消息模板,当前首先要关注这个公众号,...
  • CTF中常见的加密

    千次阅读 2019-06-02 00:35:08
    这些加密方式是很常见的,但是这次解释的很肤浅,后面有机会对部分密码来个详细分析 1.培根密码: 培根所用的密码是一种本质上用二进制数设计的,没有用通常的0和1来表示,而是采用a和b。 特征:010101010101 第...
  • 微信小程序订阅消息

    千次阅读 热门讨论 2020-03-02 15:19:21
    消息能力是小程序能力中的重要组成,以便实现服务的闭环和更优的体验。此前的小程序模板消息接口于2020年1月10日下线,2.10.0 版本开始,开发版和体验版小程序将禁止使用模板消息 fomrId。开发者可使用订阅消息功能...
  • 在上一篇博文中,我们已经学习过了消息处理机制的基础,对这个过程所涉及到的几个重要的类也有了一定的了解,如果在这方面不清楚也没看过上一篇博文的读者,请点击先阅读《 Android开发知识(五)消息处理机制的基础...
  • 结尾看开始

    千次阅读 2021-12-06 19:53:34
    结尾看开始 2021-12-06 股市理性投资 价值投资看人性 大环境;央行存款准备金率将于本月的12月15日下调0.5个百分点,那么对于明年的整体工作重心这块,也有相关的经济工作会议,那这些我就不在一一去重复...
  • 开发背景         省钱,保活、高大上。 环境准备 申请公众号; 开通微信认证(300元/年);...当触发消息推送时(如设备报警),根据openid向指定用户推送
  • ros工具可以根据消息描述为消息类型生成不同目标语言的消息代码,消息描述保存在.msg结尾的文件,放在ros包的msg子目录。 rosmsg命令行工具打印消息定义信息,查找使用该消息的源文件 消息描述规范 .msg文件包含字段...
  • 微信发送模板消息接口文档...温馨提示:请各位开发者使用微信模板消息功能前,仔细阅读上述发送模板消息接口文档,少走弯路; 一、微信公众号开发框架 <!-- 微信框架 参考:https://github.com/Wechat-Gr...
  • 导语   这篇博客主要是为大家分享一下关于Kafka集群消息...文章目录Kafka消息组织原理Kafka消息的写入操作原理Kafka消息删除原理Kafka消息检索原理Segment file 组成和物理结构index file 组成和物理结构 Kafka...
  • 基于Java自身技术实现消息方式的系统间通信基于Java自身包实现消息方式的系统间通信的方式有:TCP/IP+BIO、TCP/IP+NIO、UDP/IP+BIO以及UDP/IP+NIO 4种,下面分别介绍如何实现这4种方式的系统间通信。TCP/IP+BIO在...
  • java实现微信公众号的模板消息推送

    千次阅读 2021-09-24 10:17:59
    微信公众号提供了多种消息能力,这里我们主要讲得是模板消息,有需要其他消息实现方式的朋友可以留言,出其他实现文章。 功能介绍 模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,...
  • ORA-03113:通信通道的文件结尾

    千次阅读 2018-11-30 16:09:03
    首先看下报错情况,返回消息 “ORA-03113” 解决思路:ORA-03113主要原因是因为表空间的使用率较高导致,我们的目标是降低使用率。 (1)、查看系统表空间用量,会发现SYSAUX/SYSTEM表空间的使用率较高 SELECT...
  • 图文上传功能相对独立,因此在项目其他子系统完成之后增加这部分功能,看似简单的功能,测试时出现了“MIME 多节流出现意外的结尾。MIME 多节消息不完整”错误,问度娘,木有类似问题,谷哥之,“Unexpected end of ...
  • 微信小程序之订阅消息推送JAVA开发

    万次阅读 多人点赞 2020-01-08 11:31:02
    2019年10月份微信发布了模板消息整改公告由模板消息更改为订阅消息: 具体公告地址:https://developers.weixin.qq.com/community/develop/doc/00008a8a7d8310b6bf4975b635a401?blockType=1 (悄悄告诉大家,大家...
  • 这周姐姐入职了新公司,老板想探探他的底,看了一眼他的简历,呦呵,精通kafka,这小姑娘有两下子,既然这样,那你写一个消息队列吧。因为要用go语言写,这可给姐姐愁坏了。赶紧来求助我,我这么坚贞不屈一人,在...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 109,772
精华内容 43,908
热门标签
关键字:

常见的消息结尾方式