LTE基本架构与概念

我来了爱记之后,一直是做的4G的一个项目,现在在向5G演进。回想起来,我转到通信行业后,很多通信行业的概念和术语一直没有好好地学习和总结,导致对通信业务那块的东西都不是很清楚。本文旨在对这段时间的学习做一个总结。 LTE基本架构图 从上面架构图可以看出,整个LTE网络架构被分为4个部分,包括由E-UTRAN,EPC,UE和PDN。 在日常生活中,UE(User Equipment)可以看作是我们的手机终端, 而PDN可以看作是网络上的服务器, E-UTRAN可以看作是遍布城市的各个基站(可以是大的铁塔基站,也可以是室内悬挂的只有路由器大小的小基站),而EPC可以看作是运营商(中国移动/联通/电信)的核心网服务器,核心网包括很多服务器,有处理信令的,有处理数据,也有处理计费策略的等等。 UE User Equipment, 用户设备,就是指用户的手机,或者是其他可以利用LTE上网的设备。 eNB eNodeB, 它为用户提供空中接口(air interface), 用户设备可以通过无线连接到eNB, 也就是我们常说的基站,然后基站再通过有线链接到运营商的核心网。在这里注意,我们所说的无线通信,仅仅只是手机与基站这一段是无线的,其他部分例如基站与核心网的连接,…

是日笔记(10/18/2018)

1.把Jetty最新的release version的代码check out下来,想build一下,发现里面一堆内部module的依赖的version是project.version,导致build不了,一个个改或者用ide全局替换都不爽,Nancy花了大概0.001秒的时间,写了一个命令,执行,清清爽爽: find ./ -name pom.xml | xargs sed -i 's|${project.version}|9.4.12.v20180830|g' 就这个命令,先find出所有pom文件,然后用sed全局替换,简直能跻身运维必会命令前三甲:) 2.现在做的项目里,维护了一堆脚本,打包成RPM装到系统里,有时候想知道某个命令究竟是那个RPM装上去,stackoverflow了两条命令,利索: rpm -qf command_full_path or yum whatprovides command_full_…

Linux Namespace

Namespace是Linux虚拟网络的一个重要概念,其实不光是虚拟网络,像现在最火的容器技术也是以Namespace为基石(另外一个是cgroups),所以了解Namespace是很有必要的。 传统的Linux的许多资源是全局的,比如进程ID资源,而Namespace的 目的首先就是把这些资源做资源隔离。Linux可以在一个Host内创建许多namespace,于是那些原本是Linux全局的资源,就变成了namespace范围内的“全局”资源,而且不同namespace的资源互相不可见,彼此透明。 Linux具体将哪些全局资源做了隔离呢?看Linux相应的代码最直观: //nsproxy.h struct nsproxy{ atomic_t count; struct uts_namespace *uts_ns; struct ipc_namespace *ipc_ns; struct mnt_namespace *mnt_ns; struct pid_namespace *pid_ns; struct user_namespace *user_ns;…

慢思考者

今天Hacker News推了一篇文章我觉得很有意思:I’m a very slow thinker。作者说他反应很慢,经常是别人跟他说一件有趣的事情,他要过一段时间后才反应过来,“噢,原来这么有趣呀,哈哈”;别人问他一个深度问题,他会直接说他不知道,到第二天早上他会给出一个答案来。作者有个不错的观点是,他并不以此为耻,因为他觉得他并不是要去赢得一个辩论比赛,他习惯慢思考,只有慢思考才能真正把握问题的真正奥义,第一反应往往是不准确而且是过时的。 想想我自己,我自认为也是一个反应很慢的人,我根本没法跟那些思维极其敏捷的人相比。比如有些同事,你跟他说一个技术问题,他可以很快就能懂,并且立马给出一个解决方案,我不行,我经常要下来慢慢地从源头思考,才能有机会找到答案,我经常为此而烦恼。后来想想,我的学习曲线前期是非常慢和平缓的,但越到后期,曲线就能越陡,也不见得是一件坏事。 作者的网站还有好多他访问一些人的音频和文本,用来学英文非常好。…

写一个简单的start/stop脚本

最近要写很多脚本,比如start/stop一些应用的。下面就是我刚写的一个start/stop一个Java应用的例子:…

记一次类污染问题定位

今天项目线上测试出现了一个问题,一个War包启动失败(使用Jetty Runner启动),报的错是: Caused by: java.lang.NoSuchMethodError: org.apache.cxf.transport.AbstractTransportFactory.<init>(Ljava/util/List;Lorg/apache/cxf/Bus;)V 这个我一看第一反应是肯定是某个依赖的jar包的版本弄错了。我看了一下AbstractTransportFactory这个类,是属于cxf-api里面的(我们用的版本是2.6.2), 于是我就去Jetty解压出来的war包的目录下的lib里面看,发现里面有,cxf-api(2.6.2), cxf-core(3.1.12)等几个jar包,那就奇怪了,cxf-api的版本是对的,我甚至把它解压出来反编译了AbstractTransportFactory类来看,也是没有问题的。百思不得其解。后来同事Jun Gong提醒我说既然它报了那个错,…

用shade插件build可执行jar包

之前一直用assembly插件来build可执行的jar包,但用assembly插件有个问题,就是在build有依赖到Spring Framework的jar的时候,像META-INF目录下面的如spring.handlers和spring.schemas文件就会被互相覆盖,初了Spring Framework,我们常用的SPI,如果有两个SPI的名字一样(当然,这是不好的practice),也就是说如果META-INF/services目录有两个名字一样的文件,也会被互相覆盖。这个时候,用shade插件就有办法避免。 Shade插件如下: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.1</version> <executions&…

Spring MVC源码剖析系列(2) - DispatcherServlet工作原理之HandlerMapping

在本系列的第一篇,我剖析了DispatcherServlet的初始化过程,但还有很多东西没有说清楚,比如HandlerMapping的具体初始化,本篇就来厘清它。 如果你没有显式指定(通过xml配置文件或者Annotation)你要用的HandlerMapping类的话,DispatcherServlet默认会去classpath底下找DispatcherServlet.properties这个文件,然后从这个文件中读取出HandlerMapping类,并实例化对象。 DispatcherServlet.properties文件如下:(这里用的是4.3.9.release版本的Spring-MVC,里面的那个DefaultAnnotationHandlerMapping已经被Deprecated了,更新的版本是用的RequestMappingHandlerMapping,但这并不影响我们的分析): 我们先看一下DefaultAnnotationHandlerMapping类的继承关系: 我们看到这个DefaultAnnotationHandlerMapping最后其实是实现了ApplicationContextAware这个接口,我们要记住这个,因为它在后面会发挥重要的作用。 我们这里关注的是,究竟DefaultAnnotationHandlerMapping什么时候去将Request与Handler的Mapping关系初始化。在DefaultAnnotationHandlerMapping类里面,没有看到有这个过程,在它的父类AbstractDetectingUrlHandlerMapping里面看到了initApplicationContext()这个方法,看上去是我们要找的: 但这个initApplicationContext方法究竟是什么时候被调用的呢? 我们再回过头来看一下DefaultAnnotationHandlerMapping对象是怎样创建出来的: 我们可以看到它是调到了Spring的AbstractAutowireCapableBeanFactory的createBean方法来创建对象: 到这里,调用了doCreateBean方法,这个方法比较长,我们直奔主题吧,秘密就藏在doCreateBean方法里面调用的initializeBean方法里面(从名字已经能看出,它是负责初始化的): 这个方法也比较枯燥,我们要看的是它里面调用的applyBeanPostProcessorsBeforeInitialization方法: 我们可以看到这个方法是一一调用ApplicationContext里面的所有BeanPostProcessor的postProcessorBeforeInitialization 方法,这些BeanPostProcessor都是在AbstractApplicationContext的refresh方法里面通过调用prepareBeanFactory方法注册进来的: 其中我们要关注的是ApplicationContextAwareProcessor,我们看一下它的postProcessBeforeInitialization方法: 再看它里面调用的invokeAwareInterfaces方法:…

Building the Twelve-Factor microservice service application

A successful microservice architecture requires strong application development and DevOps practices. One of the most succinct summaries of these practices can be found in Heroku's Twelve-Factor Application manifesto. This document provides 12 best practices you should always keep in the back of your mind when building microservices. I've summarized them…

Jetty源码剖析系列(7) - 底层网络通信的细节

我们先来回顾一下Jetty负责网络连接的类ServerConnector的构造函数: 可以看到在ServerConnector的构造函数里会创建一个SelectorManager,然后加到它的bean里面(这里其实体现了Jetty的一个设计模式,就是设计了一个containner,把相关的模块放到这个containner里面,启动该container(调用doStart方法)就会连带启动里面的模块(调用模块的doStart方法), Jetty里面的Server,Connector都是这样的containner。) 我们再来看newSelectorManager方法: 就是创建一个ServerConnectorManager对象,ServerConnectorManager继承了SelectorManager类: ,我们再看一下SelectorManager的doStart方法: 可以看到在调用父类的doStart方法之前,会创建ManagedSelector,并将该selector加到SelectorManager的bean里面,随后再在调用父类的doStart方法时调用该selector的doStart方法,注意selector的数目是根据CPU的数量计算出来的, newSelector方法其实就是直接构建一个ManagedSelector对象: 我们看一下ManagedSelector的构造函数: 关于ManagedSelector,我在系列(4)里面已经有详细剖析。 此时我们先回过头去看一下ServerConnector的doStart方法: 它先调用open方法打开ServerSocketChannel,这个我在系列(6)里面有详细剖析。我们这里关注一下它调用的父类的doStart(AbstractConnector)方法: 它先调用了父类ConntainnerLifeCycle的doStart方法将它所拥有的bean(模块)都启动起来,其中就包括了我们前面加进去的SelectorManager,随即也就会把SelectorManager里面的ManagedSelector启动起来(调用它的doStart方法)。到此,我们可以看到ServerConnector会先启动Selector,然后再启动Acceptor。Connector,Selector,Acceptor,这三者的关系我画了下图来说明: 从上图可以看到,Acceptor负责接收网络连接,…