通俗理解SSL/TLS协议区别与原理

通俗理解SSL/TLS协议区别与原理

区别(历史) TLS 1.0又被叫做SSL 3.1。 换算关系: 1 2 3 TLS 1.0 = SSL 3.1 TLS 1.1 = SSL 3.2 TLS 1.2 = SSL 3.3 综上,简单说,它们的区别只是版本更迭而已。 展开说的话,历史: 1994年,NetScape公司设计了SSL协议(Secure Sockets Layer)的1.0版,但是未发布。 1995年,NetScape公司发布SSL 2.0版,很快发现有严重漏洞。 1996年,SSL 3.0版问世,得到大规模应用。 1999年,互联网标准化组织ISOC接替NetScape公司,发布了SSL的升级版TLS 1.0版。 2006年和2008年,TLS 1.1版和TLS 1.2版发布。(TLS1.2已经获得主流浏览器支持) 2008年8月,TLS 1.3版发布,性能好。移除了很多东西,速度快了很多,少了一次握手。 综上,可以先用TLS 1.2。 原理 和以前莉姐课上说的PGP协议差不多,都是三板斧:摘要、非对称加密、对称加密。 要解决的问题 1. 窃听。解决方案:加密 2. 篡改。解决方案:摘要 (解决数据完整性) 3. 冒充。解决方案:数字签名 (解决中间人攻击) 架构 ISO七层协议: TCP : 传输层 TLS : 会话层 表示层略 HTTP: 应用层 (TLS+HTTP=>HTTPS) 所以是先进行3次握手建立TCP,然后4次握手建立TLS,然后进行HTTP数据传输。 如果在TCP层抓包的话,里头是TLS加密过的数据。(中间人无法知道内容) 如果在HTTP层(应用层)收取数据的话,是已经解密过的明文。(但是中间人不太可能在应用层,除非已经嵌入到业务层代码了。) 简化版加密通信 假设用三个算法做一下加密通信,可以怎么实现呢? 定义如下: RSA: 一种非对称加密算法 AES: 一种对称加密算法 SHA1: 一种摘要算法 方案1:AES(K,data) 假如客户端是C,服务端是S,C和S要传输的数据data。 直接传明文肯定是不行,可以加密一下。用一个密钥K,加密成AES(K,data)。 这里为啥用AES呢,不用RSA呢,因为非对称加密(RSA)太慢了。 问题: 虽然别人不知道你俩传输了啥,但是可能悄悄得在中间篡改了数据,双方察觉不到。 解决方案: 加上摘要算法。 方案2:AES(K,data+SHA1(data)) 可以在数据后面加上数据的摘要,然后再加密,这样中间人一旦乱改东西马上就会被检测出来,类似于校验位。 问题: 上述方案都有一个前提,就是通信双方使用同一个K进行加解密。 那么一开始的时候怎么约定、协商这个密钥K呢? 解决方案: 先用RSA协商出一个对称密钥K。 协商密钥 最安全的方法当然是线下见面,约定一个密钥K。但是这个通信效率太低了,并发也不高。 为了避免中间人攻击,这个问题的关键点在于确认对方的身份。

聊聊page cache与Kafka之间的事儿

聊聊page cache与Kafka之间的事儿

前言 关于Kafka的一个灵魂拷问:它为什么这么快? 或者说,为什么它能做到如此大的吞吐量和如此低的延迟? 有很多文章已经对这个问题给出了回答,但本文只重点研究其中的一个方向,即对page cache的使用。先简单地认识一下Linux系统中的page cache(顺便也认识一下buffer cache)。 page cache & buffer cache 执行free命令,注意到会有两列名为buffers和cached,也有一行名为“-/+ buffers/cache”。 ~ free -m total used free shared buffers cached Mem: 128956 96440 32515 0 5368 39900 -/+ buffers/cache: 51172 77784 Swap: 16002 0 16001 其中,cached列表示当前的页缓存(page cache)占用量,buffers列表示当前的块缓存(buffer cache)占用量。用一句话来解释:page cache用于缓存文件的页数据,buffer cache用于缓存块设备(如磁盘)的块数据。页是逻辑上的概念,因此page cache是与文件系统同级的;块是物理上的概念,因此buffer cache是与块设备驱动程序同级的。 page cache与buffer cache的共同目的都是加速数据I/O:写数据时首先写到缓存,将写入的页标记为dirty,然后向外部存储flush,也就是缓存写机制中的write-back(另一种是write-through,Linux未采用);读数据时首先读取缓存,如果未命中,再去外部存储读取,并且将读取来的数据也加入缓存。操作系统总是积极地将所有空闲内存都用作page cache和buffer cache,当内存不够用时也会用LRU等算法淘汰缓存页。 在Linux 2.4版本的内核之前,page cache与buffer cache是完全分离的。但是,块设备大多是磁盘,磁盘上的数据又大多通过文件系统来组织,这种设计导致很多数据被缓存了两次,浪费内存。所以在2.4版本内核之后,两块缓存近似融合在了一起:如果一个文件的页加载到了page cache,那么同时buffer cache只需要维护块指向页的指针就可以了。只有那些没有文件表示的块,或者绕过了文件系统直接操作(如dd命令)的块,才会真正放到buffer cache里。因此,我们现在提起page cache,基本上都同时指page cache和buffer cache两者,本文之后也不再区分,直接统称为page cache。 下图近似地示出32-bit Linux系统中可能的一种page cache结构,其中block size大小为1KB,page size大小为4KB。 page cache中的每个文件都是一棵基数树(radix tree,本质上是多叉搜索树),

为何出现了trx_mysql_thread_id为0 的事务

为何出现了trx_mysql_thread_id为0 的事务

今天巡检时突然发现有很多锁等待超时的情况,原以为是一个简单的小事,一查,结果令人深思。 1. 问题现象 发现日志中出现了大量的 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 错误 2. 排查过程 发现此类情况后,挑了其中一个SQL脚本手动运行了一下,发现同样报此错误 mysql> UPDATE tbname SET column_name = 2 WHERE col_id= '25945fa285904ea59cd92a73a3850ceb' AND aYear = 2018 AND aMonth = 5; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 出现此情况,第一反应是查看是否有未提交的事务或有其他的SQL运行时也需要对该条记录进行写操作。 # 查看正在运行的sql select * from information_schema.processlist where info is not null; 结果集中并无对该表的任何操作,因此,很大可能是有未提交的事务了。 1 2 3 # 查看事务 SELECT *FROM information_schema.INNODB_TRX;   结果中确实存在大量事务,此时原本以为已经查到问题,直接将对应为提交的事务杀掉即可(已与相关人员确认可以杀) 于是把脚本准备好,准备大开杀戒 1 # 杀sql会话<br>SELECT concat('kill ',trx_mysql_thread_id,";")t_sql FROM information_schema.INNODB_TRX;   但是仔细一看,trx_mysql_thread_id全部都是0 经确认,trx_mysql_thread_id=0 的事务全部为XA事务。 3. 处理过程 因为trx_mysql_thread_id=0 的事务无法通过kill trx_mysql_thread_id 的方式处理,所以,需要回滚这些XA事务。 查看XA事务信息 mysql> xa recover; +------------+--------------+--------------+-------------------------------+ | formatID | gtrid_length | bqual_length | data | +------------+--------------+--------------+-------------------------------+ | 1096044365 | 20 | 9 | tm156393736565426841tm1333009 | | 1096044365 | 20 | 9 | tm156393708714926372tm1332251 | | 1096044365 | 20 | 9 | tm156393726166726646tm1332693 | ... +------------+--------------+--------------+-------------------------------+ 43 rows in set (0.00 sec) 拼接生成XA事务回滚脚本 # XA事务回滚命令的格式: xa rollback 'left(data,gtrid_length)','substr(data,gtrid_length+1,bqual_length)', formatID;  # 以上查出来的信息拼接结果为(以下举其中一个为例) xa rollback 'tm156393736565426841','tm1

Java CompletableFuture 详解

Java CompletableFuture 详解

Future是Java 5添加的类,用来描述一个异步计算的结果。你可以使用isDone方法检查计算是否完成,或者使用get阻塞住调用线程,直到计算完成返回结果,你也可以使用cancel方法停止任务的执行。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class BasicFuture { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService es = Executors.newFixedThreadPool(10); Future<Integer> f = es.submit(() ->{ // 长时间的异步计算 // …… // 然后返回结果 return 100; }); // while(!f.isDone()) // ; f.get(); } } 虽然Future以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的CPU资源,而且也不能及时地得到计算结果,为什么不能用观察者设计模式当计算结果完成及时通知监听者呢? 很多语言,比如Node.js,采用回调的方式实现异步编程。Java的一些框架,比如Netty,自己扩展了Java的 Future接口,提供了addListener等多个扩展方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { // SUCCESS } else { // FAILURE } } }); Google guava也提供了通用的扩展Future:ListenableFuture、SettableFuture 以及辅助类Futures等,方便异步编程。 1 2 3 4 5 6 7 8 9 10 11 final String name = ...; inFlight.add(name); ListenableFuture<Result> future = service.query(name); future.addListener(new Runnable() { public void run() { processedCount.incrementAndGet(); inFlight.remove(name); lastProcessed.set(name); logger.info("Done with {0}", name); } },

阿里P8架构师总结Java并发面试题(精选)

阿里P8架构师总结Java并发面试题(精选)

一、什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速。比如,如果一个线程完成一个任务要100毫秒,那么用十个线程完成改任务只需10毫秒。 二、线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。每个线程都拥有单独的栈内存用来存储本地数据。 三、如何在Java中实现线程? 两种方式:java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,由于线程类本身就是调用的Runnable接口所以你可以继承java.lang.Thread 类或者直接调用Runnable接口来重写run()方法实现线程。 四、Java 关键字volatile 与 synchronized 作用与区别? 1,volatile 它所修饰的变量不保留拷贝,直接访问主内存中的。 在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器)。为了性能,一个线程会在自己的memory中保持要访问的变量的副本。这样就会出现同一个变 量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者main memory中的值不一致的情况。 一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中。 2,synchronized 当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。 ①、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。 ②、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。 ③、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。 ④、当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。 ⑤、以上规则对其它对象锁同样适用。 五、有哪些不同的线程生命周期? 当我们在Java程序中新建一个线程时,它的状

联系我们

联系电话

4000-640-466

联系邮箱

service@f-li.cn

办公地址

上海黄浦区外滩源1号

谢谢,您的信息已成功发送。
请填写信息。