Статьи

Кэширование через MyBatis: настройка производительности Memcached для MyBatis

Эта статья представляет собой третье доказательство концепции из серии, описанной в предыдущей статье 4 Практические подходы для улучшения реализации уровня доступа к данным, и представляет, как реализовать Memcached через MyBatis, как добиться оптимальной конфигурации для него и личные мнения пользователей. Автор о выбранном подходе для уровня доступа к данным.

Согласно веб-сайту Memcached — это  бесплатная высокопроизводительная распределенная система кэширования объектов с открытым исходным кодом, универсальная по своей природе, но предназначенная для ускорения динамических веб-приложений за счет снижения нагрузки на базу данных. Эта характеристика описывает мощную систему кэширования хранилища значений ключей в памяти, доступную нам, разработчикам, бесплатно. На протяжении всей статьи будут рассмотрены следующие аспекты:

1. Какую выгоду получит приложение от кэширования с использованием Memcached? Функции Memcached будут подробно описаны в этом разделе.

2 . Практическая реализация проекта MemCachedPOC — в этом разделе ключевые концепции Memcached будут рассмотрены в практической реализации.

3. Резюме — Как производительность приложения была улучшена после этой реализации?

Код всех проектов, которые будут реализованы, можно найти по адресу  https://github.com/ammbra/CacherPoc    или, если вы заинтересованы только в текущей реализации, вы можете получить к нему доступ здесь:  https://github.com/ammbra. / CacherPoc / дерево / ведущий / MemCachedPOC 

Какую выгоду получит приложение от кэширования с использованием Memcached?

21- й век управляется технологией и скоростью; Время выпуска приложений сокращается с каждым днем, и каждая неделя / месяц / год приносит значительные изменения в ИТ-индустрию. В виртуальной вселенной, которая меняется так быстро, веб-приложения должны обслуживать динамический контент как можно быстрее; каждая миллисекунда имеет значение, и именно поэтому кэширование является обязательной стратегией для этих веб-приложений.

Memcached является одним из самых популярных решений для кэширования и имеет в своем портфеле таких пользователей, как

Живой журнал , Flickr , Twitter , Youtube , WordPress.com . Ниже перечислены несколько причин использования Memcached:

  •  система для кэширования данных в оперативной памяти, а не в базе данных
  •  повышает производительность чтения / записи в кэш
  • может улучшить производительность загрузки страницы
  • позволяет распределить нагрузку на кеш по отдельным серверам
  • будучи кеш-системой, предлагает эффективное использование ресурсов и значительно снижает нагрузку на базу данных
  • учитывая его список клиентов, кажется, идеально подходит для сайтов с высокой нагрузкой на базу данных

Memcached следует использовать, когда:

  •   когда статическое кэширование страниц не вариант.
  •  иметь достаточные ресурсы сервера для выделения Memcached без негативного влияния на другие сервисы.
  • Ваше веб-приложение имеет достаточный трафик, чтобы отличаться при реализации стратегии кэширования.

 Memcached не следует использовать, если:

  • веб-приложение имеет полностью анонимный трафик (сайты с низким трафиком, которые не нагружают ресурсы сервера)
  • статическое кеширование лучше подходит вашему приложению (вероятно, вы не увидите заметного преимущества, когда memcached реализован и увеличит сложность системы)
  • can negatively impact performance/scalability in this case.

Hands-on implementation of the MemCachedPOC project

Our implementation of MemCachedPOC will look as described in the diagram below:

In order to test Memcached performance the following project setup is performed:

1. Create a new Maven EJB Project from your IDE (this kind of project is platform provided by NetBeans but for those that use eclipse, here is an usefull tutorial http://theopentutorials.com/examples/java-ee/ejb3/how-to-create-a-ejb-3-x-project-using-maven-in-eclipse-part-2/). In the article this project is named MemCachedPOC.

2. Edit your project’s pom by adding required jars :

       <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.6</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-memcached</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>net.spy</groupId>
            <artifactId>spymemcached</artifactId>
            <version>2.10.6</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>     
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
        </dependency>

Note: the Memcached integration for MyBatis is built on top of the spymemcached client and this is why in our pom.xml dependencies we also need the spymemcached jar.

3.Add your database connection driver, in this case apache derby:

        <dependency>
            <groupId>org.apache.derby</groupId>
            <artifactId>derbyclient</artifactId>
            <version>10.11.1.1</version>
        </dependency>

4. Run mvn clean and mvn install commands on your project.

If you have your project in place, let’s go ahead with our implementation of MyBatis :

1. Configure under resources/com/tutorial/MemCachedPOC/xml folder the Configuration.xml file with :

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="UNPOOLED">
                <property name="driver" value="org.apache.derby.jdbc.ClientDriver"/>
                <property name="url" value="dburl"/>
                <property name="username" value="cruddy"/>
                <property name="password" value="cruddy"/>
            </dataSource>
        </environment>         
    </environments>
    <mappers>               
            <!--<mapper resource="com/tutorial/memcachedpoc/xml/EmployeeMapper.xml" /> -->
    </mappers>                   
</configuration>

2. Create in java your own SQLSessionFactory implementation. For example, create  com.tutorial.memcachedpoc.config. SQLSessionFactory

public class SQLSessionFactory {
    private static final SqlSessionFactory FACTORY;
 
    static {
        try {
            Reader reader = Resources.getResourceAsReader("com/tutorial/memcachedpoc/xml/Configuration.xml");
            FACTORY = new SqlSessionFactoryBuilder().build(reader);
        } catch (Exception e){
            throw new RuntimeException("Fatal Error.  Cause: " + e, e);
        }
    }
 
    public static SqlSessionFactory getSqlSessionFactory() {
        return FACTORY;
    }
}

3. Create your necessary bean classes, the ones that will map to your sql results, like Employee:

public class Employee implements Serializable {
    private static final long serialVersionUID = 1L;
    private Integer id;
    private String firstName;
    private String lastName;
    private String adress;
    private Date hiringDate;
    private String sex;
    private String phone;
    private int positionId;
    private int deptId;

    public Employee() {
    }

    public Employee(Integer id) {
        this.id = id;
    }


    @Override
    public String toString() {
        return "com.tutorial.memcachedpoc.bean.Employee[ id=" + id + " ]";
    }
}

4. Create the IEmployeeDAO interface that will expose the ejb implementation when injected:

public interface IEmployeeDAO {
        public List<Employee> getEmployees();   
}

5. Implement the above inteface:

@Stateless(name="memcachedDAO")
@TransactionManagement(TransactionManagementType.CONTAINER)
public class EmployeeDAO implements IEmployeeDAO {

    private static Logger logger = Logger.getLogger(EmployeeDAO.class);
    private SqlSessionFactory sqlSessionFactory;

   @PostConstruct
     public void init() {
        sqlSessionFactory = SQLSessionFactory.getSqlSessionFactory();
    }


    @Override
    public List<Employee> getEmployees() {
        logger.info("Getting employees using memcached.....");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Employee> results = sqlSession.selectList("retrieveEmployees");
        sqlSession.close();
        return results;
    }
}

6. Create the EmployeeMapper that contains the query named «retrieveEmployees»

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.tutorial.memcachedpoc.mapper.EmployeeMapper" >
    <resultMap id="results" type="com.tutorial.ehcachepoc.bean.Employee" >
        <id column="id" property="id" javaType="integer" jdbcType="BIGINT" />
        <result column="first_name" property="firstName" javaType="string" jdbcType="VARCHAR"/>
        <result column="last_name" property="lastName" javaType="string" jdbcType="VARCHAR"/>
        <result column="hiring_date" property="hiringDate" javaType="date" jdbcType="DATE" />
        <result column="sex" property="sex" javaType="string" jdbcType="VARCHAR" />
        <result column="dept_id" property="deptId" javaType="integer" jdbcType="BIGINT" />
    </resultMap> 
 
    <select id="retrieveEmployees" resultMap="results" >
        select id, first_name, last_name, hiring_date, sex, dept_id
        from employee   
    </select>  	
</mapper>

If you remember our CacherPOC setup from the previously article, then you can test your implementation if you add MemCachedPOC project as dependency and inject the IEmployeeDAO inside the MemcachedServlet. Your CacherPOC pom.xml file should contain :

      <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>MemCachedPoc</artifactId>
            <version>${project.version}</version>
        </dependency>

and your servlet should look like:

@WebServlet("/MemCachedServlet")
public class MemCachedServlet extends HttpServlet {
   private static Logger logger = Logger.getLogger(MemCachedServlet.class);

    @EJB(beanName="memcachedDAO")
    IEmployeeDAO employeeDAO;
    private static final String LIST_USER = "/listEmployee.jsp";

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String forward= LIST_USER;
        List<Employee> results = new ArrayList<Employee>();
         for (int i = 0; i < 10; i++) {
            for (Employee emp : employeeDAO.getEmployees()) {
                logger.debug(emp);
                results.add(emp);
            }
            
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                logger.error(e, e);
            }
        }
        req.setAttribute("employees", results);
        RequestDispatcher view = req.getRequestDispatcher(forward);
        view.forward(req, resp);
    }
    
}			

Run your CacherPoc implementation to check if your Data Access Layer with MyBatis is working or download the code provided at https://github.com/ammbra/CacherPoc 

But if a great amount of employees is stored in database, or perhaps the retrieval of a  number of 10xemployeesNo represents a lot of workload for the database. Also, can be noticed that the query from the EmployeeMapper.xml retrieves data that almost never changes (id, first_name, last_name, hiring_date, sex cannot change; the only value that might change in time is dept_id); so a caching mechanism can be used.

Below is described how this can be achieved using Memcached:

Caching Step 1.  Add memcached.properties  file under resources folder and try a similar configuration for it (if this file is not defined,  if not found, the client will use the default settings):

org.mybatis.caches.memcached.keyprefix=_mybatis_
org.mybatis.caches.memcached.servers=127.0.0.1:11211
org.mybatis.caches.memcached.connectionfactory=net.spy.memcached.DefaultConnectionFactory
org.mybatis.caches.memcached.asyncget = true
org.mybatis.caches.memcached.timeout = 7500
org.mybatis.caches.memcached.timeoutunit = java.util.concurrent.TimeUnit.SECONDS

            Below is the legend of the above configuration :

Property

Description

Default setting

org.mybatis.caches.memcached.keyprefix

String identifier used for key prefixation

_mybatis_

org.mybatis.caches.memcached.servers

${host}:${port}

127.0.0.1:11211

org.mybatis.caches.memcached.connectionfactory

Any class that implements

net.spy.memcached.ConnectionFactory

net.spy.memcached.DefaultConnectionFactory

org.mybatis.caches.memcached.asyncget

flag to enable/disable the async get

false

org.mybatis.caches.memcached.timeout

 timeout value when using async get

5

org.mybatis.caches.memcached.timeoutunit

timeout unit when using async get

java.util.concurrent.TimeUnit.SECONDS

Caching Step 2.
Update your  EmployeeMapper.xml to use the previous implemented caching strategy:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.tutorial.memcached.mapper.EmployeeMapper" >
   
     <cache type="org.mybatis.caches.memcached.LoggingMemcachedCache" />
      
    <resultMap id="results" type="com.tutorial.memcachedpoc.bean.Employee" >
        <id column="id" property="id" javaType="integer" jdbcType="BIGINT" />
        <result column="first_name" property="firstName" javaType="string" jdbcType="VARCHAR"/>
        <result column="last_name" property="lastName" javaType="string" jdbcType="VARCHAR"/>
        <result column="adress" property="adress" javaType="string" jdbcType="VARCHAR" />
        <result column="hiring_date" property="hiringDate" javaType="date" jdbcType="DATE" />
        <result column="sex" property="sex" javaType="string" jdbcType="VARCHAR" />
        <result column="dept_id" property="deptId" javaType="integer" jdbcType="BIGINT" />
    </resultMap> 
 
    <select id="retrieveEmployees" resultMap="results" useCache="true" >
        select id, first_name, last_name, hiring_date, sex, dept_id from employee   
    </select>  
</mapper>

By adding the line  <cache type=» org.mybatis.caches.Memcached.LoggingMemcachedCache «/>

and specifying on the query useCache=»true» you are activating Memcached cache with logging capabilities for the DataAccessLayer implementation.

Clean, build and redeploy both MemCachedPOC and CacherPoc projects; now retrieve your employees for  two times in order to allow the in-memory cache to store the values. When you run your query for the first time, your application will execute the query on the database and retrieve the results. Second time you access the employee list, your application will access the in-memory storage.

Summary — How has the application performance been improved after this implementation?

An application’s performances depend on a multitude of factors

  • how many times a cached piece of data can and is reduced by the application
  • the proportion of the response time that is alleviated by caching

The Amdhal’s law can be used to estimate the system’s speed up :

where P is proportion speed up and S is speed up.

Let’s take our implementation as example and calculate the speed up.

INFO:  2014-12-02 18:01:30,020 [EmployeeDAO] INFO  com.tutorial.memcachedpoc.dao.EmployeeDAO:38 - Getting employees.....

INFO:  2014-12-02 18:01:39,148 [JdbcTransaction] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction:98 - Setting autocommit to false on JDBC Connection [org.apache.derby.client.net.NetConnection40@1c374fd]

INFO:  2014-12-02 18:01:39,159 [retrieveEmployees] DEBUG com.tutorial.memcachedpoc.mapper.EmployeeMapper.retrieveEmployees:139 - ==>  Preparing: select id, first_name, last_name, hiring_date, sex, dept_id from employee

INFO:  2014-12-02 18:01:39,220 [retrieveEmployees] DEBUG com.tutorial.memcachedpoc.mapper.EmployeeMapper.retrieveEmployees:139 - ==> Parameters:

INFO:  2014-12-02 18:01:39,316 [retrieveEmployees] DEBUG com.tutorial.memcachedpoc.mapper.EmployeeMapper.retrieveEmployees:139 - <==  Total: 13
INFO:   2014-12-07 21:14:23,072 [EmployeeDAO] INFO  com.tutorial.memcachedpoc.dao.EmployeeDAO:38 - Getting employees using memcached.....
INFO:   2014-12-07 21:14:23,073 [MemcachedCache] DEBUG org.mybatis.caches.memcached.MemcachedCache:68 - Object key '-882220645:730093188:com.tutorial.memcached.mapper.EmployeeMapper.retrieveEmployees:0:2147483647:select id, first_name, last_name, hiring_date, sex, dept_id from employee' converted in '_mybatis_db1fc3c6fe8d04f626b0ef4dfcb647dab7a40494'
INFO:   2014-12-07 21:14:23,076 [MemcachedCache] DEBUG org.mybatis.caches.memcached.MemcachedCache:87 - Retrived object (_mybatis_db1fc3c6fe8d04f626b0ef4dfcb647dab7a40494, [com.tutorial.memcachedpoc.bean.Employee[ id=1 ], com.tutorial.memcachedpoc.bean.Employee[ id=2 ], com.tutorial.memcachedpoc.bean.Employee[ id=3 ], com.tutorial.memcachedpoc.bean.Employee[ id=4 ], com.tutorial.memcachedpoc.bean.Employee[ id=5 ], com.tutorial.memcachedpoc.bean.Employee[ id=6 ], com.tutorial.memcachedpoc.bean.Employee[ id=7 ], com.tutorial.memcachedpoc.bean.Employee[ id=10 ], com.tutorial.memcachedpoc.bean.Employee[ id=11 ], com.tutorial.memcachedpoc.bean.Employee[ id=12 ], com.tutorial.memcachedpoc.bean.Employee[ id=14 ], com.tutorial.memcachedpoc.bean.Employee[ id=8 ], com.tutorial.memcachedpoc.bean.Employee[ id=9 ]])
INFO:   2014-12-07 21:14:23,076 [EmployeeMapper] DEBUG com.tutorial.memcached.mapper.EmployeeMapper:62 - Cache Hit Ratio [com.tutorial.memcached.mapper.EmployeeMapper]: 0.9523809523809523
INFO:   2014-12-07 21:14:23,077 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=1 ]
INFO:   2014-12-07 21:14:23,077 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=2 ]
INFO:   2014-12-07 21:14:23,077 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=3 ]
INFO:   2014-12-07 21:14:23,077 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=4 ]
INFO:   2014-12-07 21:14:23,078 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=5 ]
INFO:   2014-12-07 21:14:23,078 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=6 ]
INFO:   2014-12-07 21:14:23,078 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=7 ]
INFO:   2014-12-07 21:14:23,078 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=10 ]
INFO:   2014-12-07 21:14:23,079 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=11 ]
INFO:   2014-12-07 21:14:23,079 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=12 ]
INFO:   2014-12-07 21:14:23,079 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=14 ]
INFO:   2014-12-07 21:14:23,079 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=8 ]
INFO:   2014-12-07 21:14:23,079 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=9 ]
INFO:   2014-12-07 21:14:26,079 [EmployeeDAO] INFO  com.tutorial.memcachedpoc.dao.EmployeeDAO:38 - Getting employees using memcached.....
INFO:   2014-12-07 21:14:26,080 [MemcachedCache] DEBUG org.mybatis.caches.memcached.MemcachedCache:68 - Object key '-882220645:730093188:com.tutorial.memcached.mapper.EmployeeMapper.retrieveEmployees:0:2147483647:select id, first_name, last_name, hiring_date, sex, dept_id from employee' converted in '_mybatis_db1fc3c6fe8d04f626b0ef4dfcb647dab7a40494'
INFO:   2014-12-07 21:14:26,082 [MemcachedCache] DEBUG org.mybatis.caches.memcached.MemcachedCache:87 - Retrived object (_mybatis_db1fc3c6fe8d04f626b0ef4dfcb647dab7a40494, [com.tutorial.memcachedpoc.bean.Employee[ id=1 ], com.tutorial.memcachedpoc.bean.Employee[ id=2 ], com.tutorial.memcachedpoc.bean.Employee[ id=3 ], com.tutorial.memcachedpoc.bean.Employee[ id=4 ], com.tutorial.memcachedpoc.bean.Employee[ id=5 ], com.tutorial.memcachedpoc.bean.Employee[ id=6 ], com.tutorial.memcachedpoc.bean.Employee[ id=7 ], com.tutorial.memcachedpoc.bean.Employee[ id=10 ], com.tutorial.memcachedpoc.bean.Employee[ id=11 ], com.tutorial.memcachedpoc.bean.Employee[ id=12 ], com.tutorial.memcachedpoc.bean.Employee[ id=14 ], com.tutorial.memcachedpoc.bean.Employee[ id=8 ], com.tutorial.memcachedpoc.bean.Employee[ id=9 ]])
INFO:   2014-12-07 21:14:26,083 [EmployeeMapper] DEBUG com.tutorial.memcached.mapper.EmployeeMapper:62 - Cache Hit Ratio [com.tutorial.memcached.mapper.EmployeeMapper]: 0.9545454545454546
INFO:   2014-12-07 21:14:26,084 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=1 ]
INFO:   2014-12-07 21:14:26,084 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=2 ]
INFO:   2014-12-07 21:14:26,084 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=3 ]
INFO:   2014-12-07 21:14:26,085 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=4 ]
INFO:   2014-12-07 21:14:26,085 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=5 ]
INFO:   2014-12-07 21:14:26,085 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=6 ]
INFO:   2014-12-07 21:14:26,085 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=7 ]
INFO:   2014-12-07 21:14:26,086 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=10 ]
INFO:   2014-12-07 21:14:26,086 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=11 ]
INFO:   2014-12-07 21:14:26,086 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=12 ]
INFO:   2014-12-07 21:14:26,087 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=14 ]
INFO:   2014-12-07 21:14:26,087 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=8 ]
INFO:   2014-12-07 21:14:26,087 [MemCachedServlet] DEBUG com.tutorial.cacherpoc.MemCachedServlet:42 - com.tutorial.memcachedpoc.bean.Employee[ id=9 ]

Let’s look at the time that each of our 10 times requests has scored:

the first not cached  10 times requests took about  57seconds and 51 milliseconds , while the cached requests scored a time of 27seconds and 15 miliseconds.

In order to apply Amdhal’s law for the system the following input is needed:

  • Un-cached page time:  60 seconds
  • Database time (S): 58 seconds
  • Cache retrieval time: 27 seconds
  • Proportion: 96.6% (58/60) (P)

The expected system speedup is thus:

 1 / (( 1 – 0.966) + 0.966 / (58/27)) = 1 / (0.034 + 0.966 /2.14) = 2.083 times system speedup

This result can be improved of course, but the purpose of this article was to proove that caching using Memcached over MyBatis offers a significant improvement to what used to be available before its implementation.

Learn more from:


This article is dedicated to the memory of my mother to whom I owe everything that I am.