Статистика фильтра Grails показывает производительность

У меня есть фильтр в Grails для захвата всех запросов контроллера и вставки строки в базу данных с именами контроллера, actionName, userId, датой и guid. Это прекрасно работает, но я хотел бы найти способ повысить производительность. Сейчас на все это уходит около 100 миллисекунд, из которых 70-80 мс — на создание инструкции. Я использовал как вставку объекта домена, groovy Sql, так и необработанное соединение/оператор Java. Есть ли более быстрый способ повысить производительность вставки одной записи в фильтр? В качестве альтернативы, есть ли другой шаблон, который можно использовать для вставок? Код (с использованием groovy SQL) Ниже:

class StatsFilters {

def grailsApplication
def dataSource
def filters =
{
    logStats(controller:'*', action:'*')
    {
        before = {
            if(controllerName == null || actionName == null)
            {
                return true
            }
            def logValue = grailsApplication.config.statsLogging
            if(logValue.equalsIgnoreCase("on") && session?.user?.uid != null & session?.user?.uid != "")
            {
                try{

                    def start = System.currentTimeMillis()
                    Sql sql = new Sql(dataSource)
                    def userId = session.user.uid
                    final String uuid = "I" + UUID.randomUUID().toString().replaceAll("-","");
                    String insert = "insert into STATS(ID, CONTROLLER, ACTION, MODIFIED_DATE, USER_ID) values ('${uuid}','${controllerName}','${actionName}',SYSDATE,'${userId}')"
                    sql.execute(insert)
                    sql.close()
                    def end = System.currentTimeMillis()
                    def total = end - start
                    println("total " + total)
                }
                catch(e)
                {
                    log.error("Stats failed to save with exception " + e.getStackTrace())
                    return true
                }
            }
            return true
        }
    }
}

}

И мой текущий источник данных

dataSource {

pooled = true
dialect="org.hibernate.dialect.OracleDialect"
properties {
    maxActive = 50
    maxIdle = 10
    initialSize = 10
    minEvictableIdleTimeMillis = 1800000
    timeBetweenEvictionRunsMillis = 1800000
    maxWait = 10000
    validationQuery = "select * from resource_check"
    testWhileIdle = true
    numTestsPerEvictionRun = 3
    testOnBorrow = true
    testOnReturn = true
}
//loggingSql = true

}

----------------------Решение-------------------------

Решение состояло в том, чтобы просто создать поток и сохранить статистику. Таким образом, время отклика пользователя не влияет, но сохранение выполняется почти в реальном времени. Количество пользователей в этом приложении (корпоративные внутренние, ограниченная группа пользователей) не заслуживает ничего более надежного.

void saveStatData(def controllerName, def actionName, def userId)
{
    Thread.start{
        Sql sql = new Sql(dataSource)
        final String uuid = "I" + UUID.randomUUID().toString().replaceAll("-","");
        String insert = "insert into STATS(ID, CONTROLLER, ACTION, MODIFIED_DATE, USER_ID) values ('${uuid}','${controllerName}','${actionName}',SYSDATE,'${userId}')"
        sql.execute(insert)
        sql.close()
    }
}

person Joseph    schedule 13.12.2013    source источник
comment
Мне было бы интересно узнать, может ли использование плагина Grails Executor быть лучше, Executors предназначены для того, чтобы Thread "сделано правильно", поэтому, возможно, там есть прирост производительности и надежности.   -  person Steve    schedule 16.12.2013


Ответы (1)


Лучший шаблон - не вставлять строку в фильтр, а просто добавить запись в какой-либо список и регулярно сбрасывать список в базу данных с помощью асинхронного задания (например, с помощью плагина Quartz).

Вы можете потерять некоторые данные в случае сбоя приложения, но если вы запланируете частое выполнение задания (например, каждые x минут), это не должно быть проблемой.

person lukelazarovic    schedule 13.12.2013
comment
Потеря данных будет проблемой, потому что это точно отслеживает, что происходит в приложении. Если приложение выйдет из строя, это точное время, когда нам понадобится эта информация. Тем не менее, я думаю, что буду работать над асинхронным решением, но не в пакетном режиме. Я опубликую это, если я заработаю. - person Joseph; 13.12.2013